Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > текстовые файлы


Автор: шарлотта 18.4.2017, 00:21
Здравствуйте! В текстовом файле требуется определить в каждой строке количество слов, длина которых больше 4. Вывести количество найденных слов и сами слова. Удалить из файла строку, в которых таких слов меньше всего.Если таких слов нет - оставить файл без изменений.
void CountDelete(FILE *f, FILE *g) {
    int i, j = 0, len = 0, count = 0, num_line_min, cur_num_line = 0, count_min = 1.0e+10;
    char line[100];
    char word[100];
    char buf[100] = {'\0'};
    bool key = false;
    f = fopen("first.txt", "r");
    while (fgets(line, 100, f) != NULL) {
        for (i = 0; i <= strlen(line); i++) {
            if ((line[i] != ' ') && (line[i] != '\0') {
                word[j] = line[i];
                len++;
                j++;
            } else {
                if (len > 4) {
                    word[j] = '\0';
                    count++;
                    buf[strlen(buf)] = ' ';
                    strcat(buf, word);
                }
                word[0] = '\0';
                len = 0;
                j = 0;
            }
            if (line [i] == '\0') {
                if ((count < count_min) && (count != 0)) {
                    key = true;
                    count_min = count;
                    num_line_min = cur_num_line;
                }
                strcpy(buf, buf + 1);
                printf("count = %d\n  ", count);
                if (count != 0) {
                    puts(buf);
                }
                cur_num_line++;
                count = 0;
                buf[0] = '\0';
                fflush(stdin);
            }
        }
    }
    if (key == true) {
        printf("count_min = %d\n ", count_min);
        printf("num_line_min = %d\n ", num_line_min);
        cur_num_line = 0;
        fseek(f,0L,SEEK_SET);
        while (fgets(line, 100, f) != NULL) {
            if (cur_num_line != num_line_min) {
                fputs(line, g);
            }
            cur_num_line++;
        } 
//и после этого удалить старый файл и переименовать новый
    } else {
        puts("Нет слов, длиннее 4");
    }
    fclose(f);
    fclose(g);
}
Определение нужной строки неверно работает при определении последнего слова(если я верно понимаю, из-за того, что после идет пробел) и при работе с несколькими строками. Во второй файл ничего не пишет. Не могу разобраться, как исправить ошибки. Большое спасибо за помощь!

Автор: шарлотта 18.4.2017, 00:24
Так при работе с несколькими строками

Автор: rudolfninja 18.4.2017, 09:46
Как-то у вас тяжело код написан.
Поместите между соответсвующими тегами и было бы здорово, если бы вы добавили комментарии к каждой логически обособленной части функции.
По делу сразу могу сказать, что я бы еще на вашем месте проверял line[i] на  '\n', а не только на '\0', как признак конца строки.

Автор: шарлотта 18.4.2017, 18:48
Код

void CountDelete(FILE *f, FILE *g) {
    int i, j = 0, len = 0, count = 0, num_line_min, cur_num_line = 0, count_min = 1.0e+10;
    char line[100];
    char word[100];
    char buf[100] = {'\0'};
    bool key = false;
    f = fopen("first.txt", "r");
    while (fgets(line, 100, f) != NULL) { //пока в файле есть информация, читаю строки
        for (i = 0; i <= strlen(line); i++) { //прохожу по строке
            if ((line[i] != ' ') && (line[i] != '\0') { //если не пробел и не конец строки
                word[j] = line[i]; // пишу символ в word
                len++; //увеличиваю длину
                j++; //увеличиваю счетчик (проще, наверно, будет использовать len)
            } else { //если пробел или конец строки
                if (len > 4) {//если длина слова > 4
                    word[j] = '\0'; //добавляю символ конца строки
                    count++; //увеличиваю счетчик- количество слов длиннее 4 символов
                    buf[strlen(buf)] = ' '; //все подходящие слова буду записывать в строку.добавляю в строку пробел для разделения слов
                    strcat(buf, word); //присоединяю к строке слово
                }
                word[0] = '\0'; //обнуляю слово
                len = 0; //обнуляю длину
                j = 0; //обнуляю счетчик
            }
            if (line [i] == '\0') { //если конец строки
                if ((count < count_min) && (count != 0)) { //если количество подходящих слов меньше минимального, но не равно 0
                    key = true; //ставлю ключ
                    count_min = count; //минимальное кол-во равно посчитанному
                    num_line_min = cur_num_line; //запоминаю номер строки, которую надо будет удалить
                }
                strcpy(buf, buf + 1); //так как в начале строки есть пробел, удаляю его
                printf("count = %d\n  ", count); //вывожу количество слов
                if (count != 0) { //если такие слова есть
                    puts(buf); //вывожу строку с этими словами
                }
                cur_num_line++; //увеличиваю номер строки
                count = 0; //обнуляю кол-во слов
                buf[0] = '\0'; //обнуляю буфер
                fflush(stdin);
            }
        }
    }
    if (key == true) { //если есть строка с минимальным количеством слов, но большим 0
        printf("count_min = %d\n ", count_min); //вывожу минимальное количество слов
        printf("num_line_min = %d\n ", num_line_min); //вывожу номер строки
        cur_num_line = 0; //обнуляю счетчик строк
        fseek(f,0L,SEEK_SET); //помещаю указатель на начало файла
        while (fgets(line, 100, f) != NULL) {//пока есть информация, считываю строки
            if (cur_num_line != num_line_min) { //если строка не является строкой с минимальным кол-вом нужных слов
                fputs(line, g);//пишу строку в новый файл
            }
            cur_num_line++;//увеличиваю счетчик строк
        } 
//и после этого удалить старый файл и переименовать новый
    } else {
        puts("Нет слов, длиннее 4"); //иначе вывожу сообщение, что таких слов нет
    }
    fclose(f);
    fclose(g);
}

Автор: rudolfninja 18.4.2017, 19:20
В вашем случае слово может заканчиваться и на '\n', а не только на пробел и на '\0'

Автор: шарлотта 18.4.2017, 21:03
Сделала так.
Код

void CountDelete(FILE *f, FILE *g) {
    int i, len = 0, count = 0, num_line_min, cur_num_line = 0, count_min = 1.0e+10;
    char line[100];
    char word[100];
    char buf[100] = {'\0'};
    bool key = false;
    f = fopen("first.txt", "r");
    while (fgets(line, 100, f) != NULL) {
        for (i = 0; i <= strlen(line); i++) {
            if ((line[i] != ' ') && (line[i] != '\n') && (line[i] != '\0')) {
                word[len] = line[i];
                len++;
            } else {
                if (len > 4) {
                    word[len] = '\0';
                    count++;
                    buf[strlen(buf)] = ' ';
                    strcat(buf, word);
                }
                word[0] = '\0';
                len = 0;
            }
            if (line [i] == '\n') {
                if ((count < count_min) && (count != 0)) {
                    key = true;
                    count_min = count;
                    num_line_min = cur_num_line;
                }
                strcpy(buf, buf + 1);
                printf("count = %d\n  ", count);
                if (count != 0) {
                    puts(buf);
                }
                cur_num_line++;
                count = 0;
                buf[0] = '\0';
                fflush(stdin);
            }
        }
    }
    if (key == true) {
        printf("count_min = %d\n ", count_min);
        printf("num_line_min = %d\n ", num_line_min);
        cur_num_line = 0;
        fseek(f,0L,SEEK_SET);
        while (fgets(line, 100, f) != NULL) {
            if (cur_num_line != num_line_min) {
                fputs(line, g);
            }
            cur_num_line++;
        } 
    } else {
        puts("Нет слов, длиннее 4");
    }
    fclose(f);
    fclose(g);
}

Мне кажется, теперь ошибка в том, что не обнуляет buf. При выводе второй строки соединяет часть предыдущей и новую.

Автор: xvr 18.4.2017, 23:01
Код

                    buf[strlen(buf)] = ' ';
                    strcat(buf, word);
Первый оператор затрет завершающий нуль в buf, а второй допишет к получившейся строке неизвестной длинны нечто. Результат непредсказуемый.

Автор: rudolfninja 19.4.2017, 00:15
В общем, вот рабочий вариант. Я не знаю, что пишется в файл, но слова выводит верно для каждой строки:
Код

void CountDelete(FILE *f, FILE *g) {
    int i, len = 0, count = 0, num_line_min, cur_num_line = 0, count_min = 1.0e+10;
    char line[100];
    char word[20] = { '\0' };
    char buf[100] = { '\0' };
    bool key = false;
    f = fopen("first.txt", "r");
    while (fgets(line, 100, f) != NULL) {
        line[strlen(line) - 1] = '\0';
        for (i = 0; i <= strlen(line); i++) {
            if ((line[i] != ' ') && (line[i] != '\0')) {
                word[len] = line[i];
                len++;
            }
            else {
                if (len > 4) {
                    word[len] = '\0';
                    count++;
                    buf[strlen(buf)] = ' ';
                    fflush(stdin);
                    strcat(buf, word);
                }
                memset(word, 0, 20);
                len = 0;
            }
            if (line[i] == '\0') {
                if ((count < count_min) && (count != 0)) {
                    key = true;
                    count_min = count;
                    num_line_min = cur_num_line;
                }
                strcpy(buf, buf + 1);
                printf("in string '%s' words with length more than 4 symbols %d\n", line, count);
                if (count != 0) {
                    printf("they are: %s\n", buf);
                }
                cur_num_line++;
                count = 0;
                memset(buf, 0, 100);
            }
        }
    }
    if (key == true) {
        printf("count_min = %d\n ", count_min);
        printf("num_line_min = %d\n ", num_line_min + 1);
        cur_num_line = 0;
        fseek(f, 0L, SEEK_SET);
        while (fgets(line, 100, f) != NULL) {
            if (cur_num_line != num_line_min) {
                fputs(line, g);
            }
            cur_num_line++;
        }
    }
    else {
        puts("Нет слов, длиннее 4");
    }
    fclose(f);
    fclose(g);
}

Вы не правильно очищали массив, в котором было слово и буфер со словами, которые нужно вывести. word[0]='\0' не очищает весь массив, а только зануляет первый элемент, оставив остальные элементы неизменными. Получается, что вы накладываете слова друг на друга. Я очищаю массив с помощью функции memset.
Еще я решил, что лучше будет сразу заменить символ перевода строки ('\n') на символ конца строки ('\0') при чтении строки из файла:
Код

line[strlen(line) - 1] = '\0';

В общем, разбирайтесь. Если будут вопросы или что то не будет работать, пишите, завтра попробуем найти ошибку.

Автор: шарлотта 19.4.2017, 00:26
Большое Вам спасибо! Попробую разобраться.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)