Имена файлов передаются через параметры функции main()

Есть текстовый файл содержащий русские и латинские слова. Нужно оставить в нем только те фразы, в которых содержится не менее трех слов. Имена входных файлов передаются программе при ее запуске через параметры функции main(). Если параметры при запуске программы не заданы, имена файлов вводятся с клавиатуры. Предложения может располагаться на нескольких строках, разделяются точками, а слова - пробелами, знаками препинания и символами строки. В конце файла фраза может быть без точки.

Вроде код рабочий, но переписывает до какого-то определенного момента и завершается, не могу понять в чем проблема. Еще так понимаю не правильно передаются параметры через функцию main(). Буду признателен, если поможете.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int simb(char *);

int main(int argc, char *argv[])
{
    system("chcp 1251");
    FILE * f1, * f2;
    char c, fname, str[1000], file1[50], file2[50]="t.txt";
    int len=0, i=0;
    
    while (((f1=fopen("f.txt","r"))==NULL))
    {
        printf("name file: ");
        fname=fgets(file1,sizeof(file1),f1);
        if(((f1=fopen(file1,"r"))==NULL)) puts("Error");
    }
    if ((f2 = fopen("t.txt","w")) == NULL)
    {
        puts("Error");
        system("pause");
    }
    // как-то так надо передавать или по другому?
    /*if(argc>2){
        strcpy(f1,argv[1]);
        strcpy(f2,argv[2]);
    } else {
        strcpy(f1,"f.txt");
        strcpy(f2,"t.txt");
    */}
    do
    {
        c = fgetc(f1);
        if((c=='.')||(c==EOF))
        {
            *(str+len) = (c=='.')?'.':' ';
            *(str+len+1) = '\0';
            if(simb(str))
            {
                fputs(str,f2);
                puts(str);
            }
            len=0;
        }
        else
        {
            *(str+len)=c;
            len++;
        }
    }
    while(c!=EOF);
    fclose(f1);
    fclose(f2);

    remove("f.txt");
    rename("t.txt","f.txt");
    return 0;
}
int simb(char *str)
{
    int i=0, a=0;
    while(str[i]!='\0')
    {
        if((str[i]==' ')||(str[i]==',')||(str[i]==':')||(str[i]==';')||(str[i]=='-'))
        {
            a++;
        }
        i++;
    }
    if(a<3)
        return 0;
    a=0;
    return 1;
}

Ответы (1 шт):

Автор решения: avp

Вы неправильно считаете количество слов в фразе, почему-то предполагаете, что слова разделены ровно одним разделителем и после последнего слова в фразе тоже должен быть разделитель.

Для подсчета слов нужно отслеживать состояние in_word т.е. текущий символ относится к слову или нет. При переходе от разделителей (пробелы, знаки пунктуации) к другому символу, состояние меняется и счетчик слов увеличивается.

Вот пример такого кода:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define IS_DELIM(c) (ispunct(c) || isspace(c))

int
main (int ac, char *av[])
{
  char f1_name[1024], f2_name[1024];
  if (ac < 3) {
    puts("Enter file names:");
    if (!fgets(f1_name, 1024, stdin) ||
    !fgets(f2_name, 1024, stdin))
      perror("get files\n"), exit(1);
    f1_name[strlen(f1_name) - 1] = 0;
    f2_name[strlen(f2_name) - 1] = 0;
  } else {
    strcpy(f1_name, av[1]);
    strcpy(f2_name, av[2]);
  }
  printf("input: `%s`   output: `%s`\n", f1_name, f2_name);

  FILE *in = fopen(f1_name, "r");
  if (!in)
    perror(f1_name), exit(2);
  FILE *out = fopen(f2_name, "w");
  if (!out)
    perror(f2_name), exit(2);
  int lim = 1000;
  int in_word = 0;
  int n_words = 0;
  char *str = malloc(lim + 3);
  if (!str)
    perror("malloc"), exit(3);
  int len = 0;
  
  for (;;) {

    int c = fgetc(in);
    if (c == '.' || c == EOF) { // end of phrase
      if (n_words > 2) {
        if (c == '.')
          str[len++] = c;
        str[len] = 0;
        fputs(str, out);
      }
      if (c == EOF)
        break;
      n_words = 0;
      len = 0;
      in_word = 0;
      continue;
    }

    if (len > lim)
      if ((str = realloc(str, (lim *= 2) + 3)) == 0)
        perror("realloc"), exit(3);

    // accumulate symbols of current phrase and calculate number of words in it
    str[len++] = c;
    if (!IS_DELIM(c)) {
      if (!in_word)
        n_words++;  // first character of the word
      in_word = 1;  // now state is 'in the word'
    } else          // delimiter found, now current state is 'not in the word'
      in_word = 0;
    
  } // end for (;;)

  fputs("\n", out); // for nicer output, because the last phrase outputs without '\n'
  fclose(out);
  
  return puts("End") == EOF;
}
  

О возможно незнакомых пока вам функциях (ispunct, isspace, malloc, realloc, exit, perror) прочтите в manpages (например, man ispunct (можно набивать в поисковой строке гугла))

P.S.
Вот фрагмент кода без malloc/realloc, как вы просили в комментарии

....

  int in_word = 0;
  int n_words = 0;
  char str[10000];
  int lim = 9998;
  int len = 0;

  for (;;) {

    int c = fgetc(in);
    if (c == '.' || c == EOF) { // end of phrase
      if (n_words > 2) {
        if (c == '.')
          str[len++] = c;
        str[len] = 0;
        fputs(str, out);
      }
      if (c == EOF)
        break;
      n_words = 0;
      len = 0;
      in_word = 0;
      continue;
    }

    if (len > lim) 
       fputs("Phrase too long, exited...\n", stderr), exit(3);
    
    // accumulate symbols of current phrase and calculate number of words in it
    str[len++] = c;
    if (!IS_DELIM(c)) {
      if (!in_word)
        n_words++;  // first character of the word
      in_word = 1;  // now state is 'in the word'
    } else          // delimiter found, now current state is 'not in the word'
      in_word = 0;

  } // end for (;;)

....
→ Ссылка