QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1057|回复: 10

!!文件指针到了文件结尾的怪现象

[复制链接]
发表于 2003-7-17 17:08:32 | 显示全部楼层 |阅读模式
这是一个显示文件内容的小程序,其中用了两种方法:
-------------------
/*readf.c*/
[code:1]
#include <stdio.h>
#define len 11
int main(int argc,char **argv)
{
int line,position,a;
char c=0;
char arg[len];
line=position=a=0;
if(argc<2){ printf("please enter file name\n"); exit(1);}
FILE *fp=fopen(argv[1],"r");
/*-----第一种方法-------*/
while(c!=EOF){
    c=fgetc(fp);/*每次读一个字符*/
    putchar(c);
  }
printf("\n");
/*-----再把全部字符的ascii码编号打出来--*/
rewind(fp);
c=0;
while(c!=-1)
{
  c=fgetc(fp);
  printf("%d,",c);
}
printf("\n");
/*--------第二种方法------*/
rewind(fp);
while(!(feof(fp)||ferror(fp)))
{
  fgets(arg,len,fp);/*每次读长度为len的串*/
  while(a<len-1)
  {
   if(arg[a++]=='\12')
   {
    line++;position+=a;
    printf("%s  line:%d,lenth:%d\n",arg,line,position);/*在每行结尾显示行号和长度*/
    position=0;
    a=len;
    break;
   }
  }
  if((a==len-1)&&!feof(fp))
{
  position+=len-1;
  printf("%s",arg);
}
  a=0;
}
fclose(fp);
}
[/code:1]
-------------------------
编译后执行:
bash-2.05b# ./readf file1
1dfdsgadsgfdsgdgsg
2dffsdfsdafdsfas
3asdfasdfsdfdsfdsf
4sdafdsfsddfdfdseedffsg
gfhjg

49,100,102,100,115,103,97,100,115,103,102,100,115,103,100,103,115,
103,10,50,100,102,102,115,100,102,115,100,97,102,100,115,102,97,
115,10,51,97,115,100,102,97,115,100,102,115,100,102,100,115,102,
100,115,102,10,52,115,100,97,102,100,115,102,115,100,100,102,100,
102,100,115,101,101,100,102,102,115,103,10,103,102,104,106,103,10,-1,

1dfdsgadsgfdsgdgsg
  line:1,lenth:19
2dffsdfsdafdsfas
  line:2,lenth:17
3asdfasdfsdfdsfdsf
  line:3,lenth:19
4sdafdsfsddfdfdseedffsg
  line:4,lenth:24
gfhjg
  line:5,lenth:6
gfhjg
  line:6,lenth:6
    其实文件只有5行,第1种方法没有问题,但第2种方法里打出了6行.将最后一行重复了.
    用gdb跟踪,发现读到文件末尾处时,循环回到while(!(feof(fp)||ferror(fp)))
并没有停止,而是继续了一个循环,把最后一次读的字符串重新打了一次.
  
   大家说这是为什么呢?请指教.
发表于 2003-7-18 11:01:29 | 显示全部楼层
条件错误
本该是!feof && !ferror == !(feof && ferror)
所以你现在要等到文件结尾后再读发生错误后才结束循环
回复

使用道具 举报

发表于 2003-7-18 12:36:24 | 显示全部楼层
to wsm:
!feof && !ferror 可不等于 !(feof && ferror)
误人子弟哦  
回复

使用道具 举报

发表于 2003-7-18 12:39:50 | 显示全部楼层
解决方法是把 ferror放到循环体里面,每次读完,check一下,如果出错了就break,或者干脆把fgets放到条件中去while(fgets.....)
回复

使用道具 举报

发表于 2003-7-18 12:44:15 | 显示全部楼层
!feof && !ferror 可不等于 !(feof && ferror)

呵呵 这个乱写了
回复

使用道具 举报

发表于 2003-7-18 13:07:49 | 显示全部楼层
关于如何判断文件指针是否到达流尾部的问题,APUE的例子程序提供了定式:
APUE Page99
APUE Page174
照着它写就没错
回复

使用道具 举报

 楼主| 发表于 2003-7-18 16:10:42 | 显示全部楼层
艾,楼上的朋友们也错了.
!(feof(fp)||ferror(fp))和 !feof(fp)&&!ferror(fp)等效麻,还可以少一条运算.
我也试过把if(!ferror(fp)) break;放到fgets之后,结果也也一个样.根本不起作用.

实际的问题是!feof(fp)在文件结尾多做了一次fgets才起作用呢
回复

使用道具 举报

发表于 2003-7-18 16:24:31 | 显示全部楼层
我都已经坦白了
看来是需要把eof这个字符也读入了才算是feof了
回复

使用道具 举报

 楼主| 发表于 2003-7-18 16:54:40 | 显示全部楼层
printf("%s  line:%d,lenth:%d\n",arg,line,position);/*在每行结尾显示行号和长度*/ 那行我改成了printf("%s  line:%d,lenth:%d,pointer:%d\n",arg,line,position,ftell(fp));
结果:
1dfdsgadsgfdsgdgsg
line:1,lenth:19,pointer:19
2dffsdfsdafdsfas
line:2,lenth:17 ,pointer:35
3asdfasdfsdfdsfdsf
line:3,lenth:19 ,pointer:54
4sdafdsfsddfdfdseedffsg
line:4,lenth:24 ,pointer:78
gfhjg
line:5,lenth:6 ,pointer:85
gfhjg
line:6,lenth:6 ,pointer:85
指针在85时应该在末尾了吧,再读多一个字就是-1(eof)了

用gdb察看在第4行尾 arg="fsg\n\0ggg\n\0"
第5行是 arg="gfhjg\n\0g\n\0"

呵呵 除了fgetc,fgets根本不会把-1读进去
回复

使用道具 举报

发表于 2003-7-18 23:00:44 | 显示全部楼层
文件本身根本没有什么叫eof的字符,是这样的,每个打开的流都会有两个flag,一个是标示EOF的,一个是标示FERROR的,当fgets,fread这样的函数读出的东西和参数中要求的不一致时,这两个flag会根据情况被设置,所以标准的做法是:
while(fgets(....)!=NULL){
//处理读出数据
...
}
if(ferror(...)){
//错误处理
...
}
看APUE,unix环境高级编程,里面给出了标准的处理办法
回复

使用道具 举报

 楼主| 发表于 2003-7-19 08:13:50 | 显示全部楼层
tnx!
I have no more to say yet.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-15 11:29 , Processed in 0.078854 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表