这是错误的,因为(在没有读取错误的情况下)它进入循环的时间比作者预期的时间多。如果存在读取错误,则循环永远不会终止。
考虑以下代码:
/* WARNING: demonstration of bad coding technique!! */
#include <stdio.h>
#include <stdlib.h>
FILE *Fopen(const char *path, const char *mode);
int main(int argc, char **argv)
{
FILE *in;
unsigned count;
in = argc > 1 ? Fopen(argv[1], "r") : stdin;
count = 0;
/* WARNING: this is a bug */
while( !feof(in) ) { /* This is WRONG! */
fgetc(in);
count++;
}
printf("Number of characters read: %u\n", count);
return EXIT_SUCCESS;
}
FILE * Fopen(const char *path, const char *mode)
{
FILE *f = fopen(path, mode);
if( f == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return f;
}
该程序将始终输出比输入流中的字符数大一个的字符(假设没有读取错误)。考虑输入流为空的情况:
$ ./a.out < /dev/null
Number of characters read: 1
在这种情况下,feof()
在读取任何数据之前调用,因此它返回false。进入循环,fgetc()
将其调用(并返回EOF
),并增加计数。然后feof()
被调用并返回true,从而导致循环中止。
在所有此类情况下都会发生这种情况。 在对流进行的读取遇到文件结尾之后feof()
,才会返回true 。的目的不是检查下一次读取是否到达文件末尾。的目的是区分读取错误和到达文件末尾。如果返回0,则必须使用/ 来确定是否遇到错误或是否消耗了所有数据。如果返回则类似。 仅在 fread返回零或返回后才有用。在此之前,将始终返回0。feof()
feof()
fread()
feof
ferror
fgetc
EOF
feof()
fgetc
EOF
feof()
在调用之前,始终有必要检查读取的返回值(fread()
,或fscanf()
,或fgetc()
)feof()
。
更糟糕的是,考虑发生读取错误的情况。在这种情况下,fgetc()
return EOF
,feof()
return false和循环永远不会终止。在所有使用情况下,while(!feof(p))
都必须在循环内至少检查ferror()
,或者至少应将while条件替换为,while(!feof(p) && !ferror(p))
否则很可能会发生无限循环,可能会产生各种垃圾,例如无效数据正在处理中。
因此,总而言之,尽管我不能确定地说永远不会出现写“ while(!feof(f))
” 在语义上正确的情况(尽管循环内必须进行另一次检查,但要有一个中断以避免在读取错误时发生无限循环) ),这种情况几乎肯定总是错误的。即使出现了正确的案例,这也是非常错误的习惯,以至于它不是编写代码的正确方法。任何看到该代码的人都应立即犹豫并说:“那是一个错误”。并可能对作者打耳光(除非作者是您的老板,在这种情况下,建议您谨慎行事。)
feof()
控制循环不好