feof使用陷阱

3.14  使用feof函数的陷阱

代码示例

 

  1. int main(){  
  2.     FILE *fp;  
  3.     char line[100];//假定要打开的文件每行小于100个字符  
  4.     fp = fopen("/etc/passwd", "r");  
  5.     while(!feof(fp)){  
  6.         fgets(line, sizeof(line), fp);  
  7.         printf("%s", line);  
  8.     }  
  9.     fclose(fp);  
  10.     return 0;  
  11. }  

现象&后果

上述代码是想逐行打印文件passwd,但运行程序之后,发现文件最后一行被打印输出了两次。

Bug分析

feof函数的功能是检查一个stream在当前其文件结束标志是否被置位,如果已经置位,返回非零值,否则返回零。一个stream的文件结束标志是由当前时间之前的最后一次相关操作(包括读、seek等操作)设置的。在上述代码while循环中,当fgets在读取文件最后一行后,文件结束标志还并没有被置位,所以下一次while循环判断依然可以进来,此时再一次调用fgets将返回null(这时文件结束标志被置位),而line中的字符串保持不变,依然为上一次的结果,此时再一次打印line,所以出现最后一行被打印输出两次。

对上述代码的修改有两种。第一种直接用fgets函数返回结果作while条件判断。第二种依然用feof函数返回结果作条件判断,但需要放在fgets函数调用之后,放在一个if条件判断中,如果满足就break这个循环,而while的条件为常量true。下面的正确代码采用第二种方式。

正确代码

 

  1. int main(){  
  2.     FILE *fp;  
  3.     char line[100];//假定要打开的文件每行小于100个字符  
  4.     fp = fopen("/etc/passwd", "r");  
  5.     while(true){  
  6.         fgets(line, sizeof(line), fp);  
  7.         if(!feof(fp)){  
  8.             printf("%s", line);  
  9.         }else{  
  10.             break;  
  11.         }  
  12.     }  
  13.     fclose(fp);  
  14.     return 0;  
  15. }  

编程建议

上述代码中,fgets函数的调用会修改文件结束标志,其他还会修改文件结束标志的类似的函数还有:fgetc、fgets、fread、fseek、getc、getchar、gets等,所以,在使用这些函数的时候也要注意这个Bug中展示的问题。

posted @ 2017-05-06 00:15  T.X  阅读(313)  评论(0)    收藏  举报