Fgets() проблемы с циклом for в C

Почему я получаю следующий вывод, когда fgets находится вне цикла for:

Jim, Engineer

Jim, Engineer

Jim, Engineer

Jim, Engineer

и следующий вывод, когда fgets находится внутри цикла for:

Jim, Engineer

Pam, Nurse

Scar, Troublemaker

John, Smith

int main()
{
    int i;
    char line[255];
    FILE *fpointer = fopen("employees.txt", "r");

    for (i=0; i < 4; i++){
        fgets(line, 255, fpointer);
        printf("%s", line);
    }
    fclose(fpointer);

    return 0
}

внутри fget() «i» не передается в качестве аргумента, так как же он все еще перебирает каждую строку в файле .txt?

fpointer обновляется внутри fgets
Vagish 29.05.2019 04:44

я не понимаю

user10003651 29.05.2019 04:45

Вы хотите сказать, что fgets(...); for(...) printf(...) печатает одну и ту же строку 4 раза? Почему это удивительно?

William Pursell 29.05.2019 04:46

Каждый fgets читает одну строку, помещая ее в line. Если вы вызовете его 4 раза, печатая line после каждого вызова, вы напечатаете эти 4 строки. Если вы вызовете его один раз вне цикла, то цикл просто напечатает первую строку 4 раза.

Tom Karzes 29.05.2019 04:49

Нет Воли, я пытаюсь понять, как fgets() увеличивается, когда я не передал в него инкрементатор "i"

user10003651 29.05.2019 04:49

Спасибо, Том, как мне проверить твой ответ?

user10003651 29.05.2019 04:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
81
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

fgets прочитает файл с помощью fpointer (думайте об этом как о курсоре) и увеличит его. Поэтому каждый раз, когда вы используете fgets, вы продвигаетесь вперед в файле.

Хотя у вас уже есть прекрасный ответ, объясняющий перемещение индикатор позиции файла с файловым потоком каждый раз, когда выполняется вызов fgets() (или любой другой функции ввода), еще один необходимый момент, который нельзя упускать из виду, — это Всегда проверяйтевернуть функции ввода. чтобы убедиться, что вызов прошел успешно до, используя прочитанную информацию.

В вашем случае при использовании цикла for, если в файле менее 4 строк или если возникает ошибка потока, вы вслепую передаете line в printf для вывода, даже не зная, содержит ли он действительные данные. Это приглашение для Неопределенное поведение. Всегда проверяйте возврат.

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

Чтобы прочитать все строки в файле, предполагая, что это был ваш ввод, вы должны просто сделать:

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

int main()
{
    char line[255];
    FILE *fpointer = fopen("employees.txt", "r");

    while (fgets(line, 255, fpointer)) {    /* control read loop with fgets */
        line[strcspn (line, "\r\n")] = 0;   /* trim \n from end of line */
        puts (line);
    }
    fclose(fpointer);

    return 0;
}

Если вы намерены прочитать определенное количество строк, просто включите счетчик, например. читать 4 строчки:

int main()
{
    size_t n = 0;
    char line[255];
    FILE *fpointer = fopen("employees.txt", "r");

    /* control read loop with counter and fgets */
    while (n < 4 && fgets(line, 255, fpointer)) {
        line[strcspn (line, "\r\n")] = 0;   /* trim \n from end of line */
        puts (line);
        n++;
    }
    fclose(fpointer);

    return 0;
}

Таким образом, вы включили возврат fgets() и количество строк в условный цикл.

(Примечание: использование strcspn, которое возвращает количество символов в строке, НЕ являющихся частью набора исключений "\r\n", обеспечивает длину строки без учета конца строки, позволяя вам просто перезаписать первый символ конца строки с помощью '\0' или его числовой эквивалент 0. По сути, он делает следующее:)

        size_t len = strlen (line);
        if (len && len - 1 == '\n')
            line[--len] = 0;        /* trim \n from end of line */ 

Дайте мне знать, если у вас есть дополнительные вопросы.

Другие вопросы по теме