我在这里读到feof
或更准确地说,使用!feof
在文件中搜索信息是一个坏习惯。
我所理解的是,它是坏的,因为它在调用函数或进程或类似的东西之前从FILE
指针读取信息。
有一个do
/while
循环,内部有fscanf
,!feof
作为退出条件,不是很好吗?
这是我做的一个搜索函数
typedef struct
{
char lname[20] , fname[20];
int nchildren;
}employee;
void searchemployee(char *filename , char *str)
{
employee e;
FILE *f;
int c;
f = fopen(filename, "r");
if (f == NULL)
printf("file couldn't be loaded\n");
else {
c = 0;
do {
fscanf(f, "%s %s %d\n", e.fname, e.lname, &e.nchildren);
if (strcmp(e.fname, str) == 0)
c = 1;
} while (c == 0 && !feof(f));
if (c != 1)
printf("employee not found\n");
else
printf("employee : %s %s| children : %d\n", e.fname, e.lname, e.nchildren);
}
fclose(f);
}
2条答案
按热度按时间xuo3flqw1#
函数
feof
的返回值指定前一个输入操作是否已经遇到文件结尾。此函数不指定下一个输入操作是否将遇到文件结尾。问题是
如果
fscanf
由于遇到文件末尾而失败并返回EOF
,则它将不向e.fname
写入任何内容。如果这种情况发生在循环的第一次迭代中,那么
e.fname
的内容将是不确定的,并且随后的函数调用strcmp(e.fname,str)
将调用未定义的行为(即,您的程序可能崩溃),除非e.fname
碰巧包含终止空字符。如果这不是在第一次迭代中发生的,而是在循环的后续迭代中发生的,那么
e.fname
的内容将包含前一次循环迭代的内容,因此您实际上将处理fscanf
的最后一次成功调用两次。在这个特定的例子中,两次处理
fscanf
的最后一次成功调用是无害的,只是会稍微浪费CPU和内存资源,但是在大多数其他的例子中,两次处理最后一次输入会导致程序不能正常工作。有关详细信息,请参见以下问题:
Why is “while( !feof(file) )” always wrong?
如果将循环更改为
从而在循环的中间检查循环条件,则上述问题将消失。
但是,一般来说,检查
fscanf
的返回值比调用feof
更好,例如:另外,您不需要标记变量
c
。一部分放进环里,就像这样
另一个问题是,当将
%s
与scanf
或fscanf
一起使用时,通常还应添加宽度限制,以防止可能出现buffer overflow。例如,如果e.fname
的大小为100
字符,则应使用%99s
来限制写入99
的字节数加上终止空字符。ztigrdn82#
调用
feof
会询问“在这个流上的前一个操作中遇到了文件结束还是错误?”如果你使用
feof
来回答这个问题,那就好了。但是,你使用feof
来期望你的next操作将从文件中读取数据,那就错了。前一个操作可能在文件结束之前**就结束了,所以feof
说“no”,但是文件中没有留下任何要读取的数据。标准C库中的文件/流函数被设计成当到达文件尾时会告诉你它们失败了。你应该使用每个函数提供的返回值(或其他指示)来测试问题:
请注意,调用
fscanf
然后调用feof
将告诉您fscanf
是否遇到了文件尾或输入错误,但它不会告诉您fscanf
是否读取了一些输入并分配了一些值,但遇到了文件尾并且没有完成。如果您只阅读一个内容,则可以使用fscanf
后跟feof
,但是更复杂的程序可能需要区分部分输入。