feof使用陷阱
3.14 使用feof函数的陷阱
代码示例
- int main(){
- FILE *fp;
- char line[100];//假定要打开的文件每行小于100个字符
- fp = fopen("/etc/passwd", "r");
- while(!feof(fp)){
- fgets(line, sizeof(line), fp);
- printf("%s", line);
- }
- fclose(fp);
- return 0;
- }
现象&后果
上述代码是想逐行打印文件passwd,但运行程序之后,发现文件最后一行被打印输出了两次。
Bug分析
feof函数的功能是检查一个stream在当前其文件结束标志是否被置位,如果已经置位,返回非零值,否则返回零。一个stream的文件结束标志是由当前时间之前的最后一次相关操作(包括读、seek等操作)设置的。在上述代码while循环中,当fgets在读取文件最后一行后,文件结束标志还并没有被置位,所以下一次while循环判断依然可以进来,此时再一次调用fgets将返回null(这时文件结束标志被置位),而line中的字符串保持不变,依然为上一次的结果,此时再一次打印line,所以出现最后一行被打印输出两次。
对上述代码的修改有两种。第一种直接用fgets函数返回结果作while条件判断。第二种依然用feof函数返回结果作条件判断,但需要放在fgets函数调用之后,放在一个if条件判断中,如果满足就break这个循环,而while的条件为常量true。下面的正确代码采用第二种方式。
正确代码
- int main(){
- FILE *fp;
- char line[100];//假定要打开的文件每行小于100个字符
- fp = fopen("/etc/passwd", "r");
- while(true){
- fgets(line, sizeof(line), fp);
- if(!feof(fp)){
- printf("%s", line);
- }else{
- break;
- }
- }
- fclose(fp);
- return 0;
- }
编程建议
上述代码中,fgets函数的调用会修改文件结束标志,其他还会修改文件结束标志的类似的函数还有:fgetc、fgets、fread、fseek、getc、getchar、gets等,所以,在使用这些函数的时候也要注意这个Bug中展示的问题。

浙公网安备 33010602011771号