fgets在非空文件上返回null

时间:2020-01-09 21:36:31

标签: c file-io null fgets

我正在尝试从文件中成对读取非特定数量的整数。我也想跳过以#开头的行。我的问题是什么都没印出来。当我尝试打印fgets返回的值时,它打印为null。我会很感激一点帮助,因为我对C不太熟悉,如果您不专注于feof,因为我已经阅读了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 个答案:

答案 0 :(得分:1)

您不应在feof()条件下检查while。参见Why is “while ( !feof (file) )” always wrong?

循环应为:

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

答案 1 :(得分:1)

首先,回答问题的标题:fgets()在文件结尾而不是在文件为空时返回NULL

无论如何,您在while循环中的测试不正确:

  • feof()仅在您已经尝试读取并且已经以失败的读取达到文件结尾时给出真实的结果。由于read会尝试为您提供尽可能多的字节...或者如果文件末尾没有字节,那么获取文件末尾条件的唯一方法是读取失败后 >。检查fgets()的结果要好得多,因为如果无法读取任何内容,它将返回NULL。 (而不是最后一次阅读)

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

    或者只是

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

    会好得多。另外,请参见如何使用sizeof运算符来使用已用缓冲区的大小,而不是在两个位置重复(且容易出错)实际字节数。如果决定更改缓冲区的大小,则还需要更改要在fgets()调用中读取的实际字节数,从而有可能忘记其中之一而遇到麻烦。 / p>

  • 您只能在 !feof() counter == 6 时(仅在计数器相等时才进入循环)到6,尽管您尚未达到EOF ,但这是不正确的。请以为您仅在两种情况都为假时才退出循环(这意味着{{1 }}返回true ,并且还返回{strong> feof()),那么您最好编写:

    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已经是一个char指针。最好将其传递给buff。n但是,相反,您需要将指针传递给您正在读取的变量,因此需要将其更正为:

    buff

    不这样做将导致难以实现的未定义行为,因为使用未初始化的变量(更多地是指向变量的指针)将使代码起初可以工作,但是在生产一段时间后会失败...这是一个非常严重的错误

已纠正所有这些错误的代码应如下所示:

pru.c

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

运行代码显示:

#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在这里毫无用处(以及您不要求的其他许多事情,代码中的错误),如果确实如此,则最好发布一个示例,该示例仅显示失败行为,如您应该阅读的页面How to create a Minimal, Complete, and Verifiable example所建议的那样,我建议您这样做。