【问题标题】:fgets returns null on non empty filefgets 在非空文件上返回 null
【发布时间】:2020-01-09 21:36:31
【问题描述】:

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

【问题讨论】:

  • 这个语句 if(fopen==NULL){ 或者这个 if(strcmp(buff[0],"#")){ 没有意义。
  • counter == 6 应该是 counter &lt; 5
  • 在哪里查看fgets()的值?
  • Azzarian “如果您不关注 feof,我将非常感激,因为我已经阅读了为什么 feof 不好”,这会适得其反,因为 while(!feof(fd) ... 是一个重要的问题的一部分。考虑修复它并查看编译器警告。

标签: c file-io null fgets


【解决方案1】:

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

不管怎样,你在while循环中的测试是不正确的:

  • feof() 仅在您已经尝试读取并且您已经以不成功的读取到达文件末尾时才会给出真实结果。由于read 试图为您提供尽可能多的字节......或者如果文件结束则根本不提供,获得文件结束条件的唯一方法是在您未能读取某些内容之后。检查fgets() 结果要好得多,因为它现在无法读取任何内容时返回NULL。 (而不是在最后一次阅读中)所以

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

    或者只是

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

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

  • 您命令仅在 !feof()counter == 6 时才留在循环中(首先,这将使控件在计数器等于 6 时进入循环,尽管如此您是否已达到 EOF,这是不正确的)认为您只有在两个条件都为 false 时才退出循环(这意味着 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(&amp;buff, "%d %d", .... 行中,您不需要传递&amp;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

最后提示一下:

尽管您有兴趣了解循环下降的原因,而不是为什么 feof() 在这里没有用(以及许多其他您不要求的事情您的代码有错误),如果确实如此,您最好发布一个示例仅显示失败的行为,正如您应该阅读的页面How to create a Minimal, Complete, and Verifiable example 所建议的那样,我建议您去做。

【讨论】:

    【解决方案2】:

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

    循环应该是:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-05
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-15
      • 1970-01-01
      相关资源
      最近更新 更多