从文本中读取字符——feof函数问题
作者:互联网
feof()函数
函数原型:int feof(FILE *fp);
函数功能:检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0,文件结束符只能被clearerr()函数清除
(函数feof()总是在读完文件所有内容后再执行一次读文件操作(将文件结束符读走,但不显示)才能返回真(非0)值)
函数 feof 只用于检测流文件,当文件内部位置指针指向文件结束时,并未立即置位 FILE 结构中的文件结束标记,只有再执行一次读文件操作,才会置位结束标志,此后调用 feof 才会返回为真
请读者注意下这句话:“只有再执行一次读文件操作,才会置位结束标志”
为了更深入理解上面这句话,下面使用断点调试来分析读取文本文件时feof函数的作用以及文本文件指针的移动,
在往下看之前读者需要先了解下fscanf和ftell函数
ftell()函数
函数原型:long ftell(FILE *fp);
函数功能:读取当前文件指针位置,若函数调用成功,则返回文件的当前读写位置,否则返回-1L
(函数ftell()用于相对于文件起始位置的字节偏移量来表示返回的当前位置指针)
fscanf()函数
返回值:返回成功读取的参数个数,若读取失败返回-1
下面就上代码了
void ReadMap(char (*map)[N], FILE *fp) { int i, j; int m, n; i = j = 0; while(!feof(fp)) /* 未读到文件末尾 */ { n = fscanf(fp, "%c", &map[i][j]); m = ftell(fp); j++; if (map[i][j] == '\n') { i++; j = 0; } } }
断点调试的位置如下:
在开始调试前,先在E盘根目录下创建一个文本文件ww.txt,输入123保存
下面就开始调试了:
第一次:
执行了两条语句
n = fscanf(fp, "%c", &map[i][j]);
m = ftell(fp);
文本文件的第一个字符'1',被存入到数组中,fscanf返回成功入读的参数个数(若失败返回-1),这里fscanf的返回值是1赋值给了n,表示成功读取了一个字符,此时文件指针向后移动了一次,所以ftell的返回值是1赋值给m,此时文件指针的位置如下
第二次:
第二次读取时,文本文件的第二个字符'2',被存入到数组中,fscanf返回成功入读的参数个数返回值为1赋值给n,此时文件指针又向后移动了一次,所以ftell的返回值是2
此时文件指针的位置如下
第三次:
第二次读取时,文本文件的第三个字符'3',被存入到数组中,fscanf返回成功入读的参数个数返回值为1赋值给n,此时文件指针又向后移动了一次,所以ftell的返回值是3赋值给m
此时文件指针的位置如下
后面的就是关键点了,此时文件指针已经指向了EOF(注意:EOF并不是一个字符,也不是文件中实际存在的内容,EOF只是文件结束的一个标志,这个要清楚,上面的图之所以把EOF写出来是
为了方便读者理解)
再次回到时,并不会判断为假直接退出,而是会再执行一次循环体,也就是文章开头所说的“当文件内部位置指针指向文件结束时,并未立即置位 FILE 结构中的文件结束标记,只有再执行一次读文件操作,才会置位结束标志,此后调用 feof 才会返回为真”
意思是while执行了4次,虽然文本文件中只有3个字符,下面来瞧一瞧第四次的循环中变量的值有什么变化
局部变量的值可以看出一些问题,n的值为-1,意味着fscanf读取失败了,那么意味着数组中的元素没有变化,还是之前的123字符,下面检查一下数组中的值
(注:数组是提前初始化过的,全部元素赋值为空格' ')
从上面的局部变量还可以注意到一个问题,就是m的值没有改变,意思就是在fscanf读取失败后指针的仍然指向EOF
到这里四次循环就结束了,第五次判断的时候feof返回值为非零,结束循环
标签:文件,读取,fscanf,函数,ftell,文本,feof,指针 来源: https://www.cnblogs.com/lanhaicode/p/10651285.html