非空文件上的 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)
的指针,这不是你想要的(fopen
是 always != 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 您应该阅读并且我建议您阅读的页面。
我正在尝试从文件中成对读取非特定数量的整数。我还想跳过以 # 开头的行。我的问题是什么都没有打印出来。当我尝试打印 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()
结果,因为 returnsNULL
现在无法读取任何内容。 (而不是在上次阅读中)所以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)
的指针,这不是你想要的(fopen
是 always!= 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 您应该阅读并且我建议您阅读的页面。