fgets возвращает ноль в непустом файле - PullRequest
1 голос
/ 10 января 2020

Я пытаюсь прочитать из файла не указанное c количество целых чисел в парах. Я также хочу пропустить строки, начинающиеся с #. Моя проблема в том, что ничего не печатается. Когда я попытался напечатать значение, возвращаемое fgets, он вывел ноль. Я был бы очень признателен за небольшую помощь, так как я не очень опытен с C, и я был бы очень признателен, если бы вы не сосредоточились на feof, поскольку я уже прочитал, почему это плохо.

Файл выглядит так это:

#This must
#be
#skipped
1233 14432
4943928  944949
11233   345432

И код:

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

typedef struct{
int start;
int end;
}path;
int main()
{
    path* array;
    array=malloc(5*sizeof(path));
    if(array==NULL){
    printf("Error allocating memory\n");
    abort();
    }


    FILE* fd=fopen("File.txt","r");
    if(fd==NULL){
    printf("Error opening file\n");
    abort();
    }
    char buff[200];
    int counter=0;
    if(fopen==NULL){
       printf("Error opening file\n");
        abort();
    }
    char c;
    while(!feof(fd)||counter==6){
        fgets(buff,200,fd);
        c=buff[0];
        if(strcmp(buff[0],"#")){
            continue;
        }
        sscanf(&buff,"%d %d",array[counter].start,array[counter].end);
        printf("%d\t%d\n",array[counter].start,array[counter].end);
        counter++;
    }


    fclose(fd);
    free(array);
    return 0;
}

Ответы [ 2 ]

1 голос
/ 10 января 2020

Во-первых, отвечая на заголовок вашего вопроса: fgets() возвращает NULL в конце файла, а не когда файл пуст.

В любом случае, ваш тест в while l oop неверно:

  • feof() дает истинный результат только тогда, когда вы уже попытались прочитать и уже достигли конца файла с неудачным чтением . * * * * * * * * * * * * * * * * * * * * * * * * * * * *, Если конец файла 1013 * пытается дать вам столько байтов, сколько он может ... или ни одного вообще, единственный способ получить условие конца файла - это после того, как вам не удалось прочитать что-то . Гораздо лучше проверить результат fgets(), так как он возвращает NULL при невозможности что-либо прочитать сейчас. (и не в последнем прочтении), поэтому

    while(fgets(buff, sizeof buff, fd) != NULL)
    

    или просто

    while(fgets(buff, sizeof buff, fd))
    

    будет намного лучше. Также посмотрите, как я использую оператор sizeof, чтобы использовать размер используемого буфера, вместо того, чтобы повторять (и быть подверженным ошибкам) ​​фактическое количество байтов в двух местах. Если вы решите изменить размер буфера, вам также потребуется изменить фактическое количество байтов для чтения в вызове fgets(), что позволит забыть об одном из них и столкнуться с проблемой.

  • Вы приказываете оставаться в l oop только тогда, когда !feof() ИЛИ когда counter == 6 (во-первых, это заставит элемент управления ввести l oop когда счетчик равен 6, , несмотря на то, что вы достигли EOF или нет , это не может быть правильным) Думайте, что вы выходите из l oop только когда оба условия ложны ( это значит feof() возвращает true , а также counter != 6), вам лучше написать:

    while(fgets(buff, sizeof buff, fd) && counter < max_number_of_iterations)
    
  • Тест

    if(strcmp(buff[0],"#"))
    

    также неверно, так как buff[0] является символом (действительно, это первый символ, читаемый в буфере, а "#" является строковым литералом (не символом). Возможно, вы получили по крайней мере предупреждение от компилятора, из которого вы не говорите ни слова. Вам лучше проверить оба символа на равенство, как в

    if (buff[0] == '#')  /* this time '#' is a character literal, not a string literal */
    
  • в строке

    if (fopen == NULL)
    

    fopen сам по себе является указателем на библиотечную функцию fopen(3), что не то, что вам нужно (fopen всегда != NULL), но

    if (fd == NULL){
    

    (что вы делали раньше, поэтому вам лучше исключить этот код)

  • вы определяете char c;, затем инициализируете его первым символом buff, а затем вообще не используете его. Это не оказывает никакого влияния на ваш код, но это плохой стиль и мешает сопровождающим в будущем.

  • в строке sscanf(&buff, "%d %d", .... вам не нужно пропускать &buff, тогда как buff это уже указатель на символ . Лучше передать его buff .n Но вместо этого вам необходимо передать указатели на переменные, которые вы читаете , поэтому вам нужно исправить это в:

    sscanf(buff, "%d%d", &array[counter].start, &array[counter].end);
    

    без этого создаст Undefined Behavior , который будет трудно реализовать, так как использование неинициализированных переменных (и, более того, указателей на переменные) вначале заставит код, вероятно, работать, но потерпит неудачу, когда он попадет в производство. какое-то время ... это очень серьезная ошибка .

Ваш код со всеми исправленными ошибками должен выглядеть следующим образом:

pru. c

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

#define N (5)  /* I have  defined this constant so you can 
                * change its value without having to go all 
                * the code for occurrences of it and 
                * changing those */

typedef struct{
    int start;
    int end;
} path;

int main()
{
    path* array = malloc(N*sizeof(path)); /* better declare and init */
    if(array==NULL){
        printf("Error allocating memory\n");
        abort();  /* have you tried exit(EXIT_FAILURE); ?? */
    }

    FILE* fd=fopen("File.txt","r");
    if(fd==NULL){
        printf("Error opening file\n");
        abort();
    }
    char buff[200];
    int counter=0;
    while(fgets(buff, sizeof buff, fd) && counter < N){
        if(buff[0] == '#'){
            continue;
        }
        sscanf(buff, "%d %d", &array[counter].start, &array[counter].end);
        printf("%d\t%d\n", array[counter].start, array[counter].end);
        counter++;
    }

    fclose(fd);
    free(array);

    return 0;
}

Запуск кода показывает:

$ pru
1233    14432
4943928 944949
11233   345432

с File.txt, который вы отправили.

Наконец, подсказка:

Несмотря на ваш интерес к знанию только причин вашего oop падения, а не к тому, почему feof() здесь бесполезен (и ко многим другим вещам, о которых вы просто не просите и что не так в вашем коде), если это действительно так, вам лучше опубликовать пример , который только показывает ошибочное поведение в соответствии с рекомендациями на странице Как создать минимальный, полный и проверяемый пример , который вы должны прочитать, и который я рекомендую вам сделать.

1 голос
/ 10 января 2020

Вы не должны проверять feof() в состоянии while. См. Почему «while (! Feof (file))» всегда неверно? .

Значение l oop должно быть:

while (fcounter < 5 && fgets(buff, 200, fd))
...