非空文件上的 fgets returns null

fgets returns null on non empty file

我正在尝试从文件中成对读取非特定数量的整数。我还想跳过以 # 开头的行。我的问题是什么都没有打印出来。当我尝试打印 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;
}

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

循环应该是:

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

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

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

  • feof() 只有当您 已经尝试读取并且您已经到达文件末尾且读取失败 时才会给出真实结果。由于 read 试图为您提供尽可能多的字节...或者 none 如果文件结束,获得文件结束条件的唯一方法是 在您失败之后读点东西。最好检查 fgets() 结果,因为 returns NULL 现在无法读取任何内容。 (而不是在上次阅读中)所以

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

    或者只是

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

    会好得多。另外,看看我如何使用 sizeof 运算符来使用已用缓冲区的大小,而不是在两个地方重复(并且容易出错)实际字节数。如果您决定更改缓冲区的大小,您还需要更改 fgets() 调用中要读取的实际字节数,从而有可能忘记其中一个 运行陷入困境。

  • 你命令只在 !feof()counter == 6 时留在循环中(首先,这将使控制当 counter 等于 6 时进入循环,不管你是否达到 EOF,这都不正确)认为你 只有在两种情况下才退出循环是false(这意味着feof() returns 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) 的指针,这不是你想要的(fopenalways != 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);
    

    不这样做会导致难以实现的未定义行为,因为使用未初始化的变量(以及更多关于变量的指针)会使代码可能一开始工作,但是当它投入生产一段时间后就失败了……这是一个非常严重的错误

您的代码在更正了所有这些错误后应该如下所示:

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 你 posted.

最后提示一下:

尽管您有兴趣了解 只是 循环下降的原因,而不是 feof() 在这里没用的原因(以及许多其他您不需要的东西) '要求并且在你的代码中是错误的),如果确实如此,你最好post一个例子只显示失败的行为 How to create a Minimal, Complete, and Verifiable example 您应该阅读并且我建议您阅读的页面。