刚开始学习C语言的时候,关于文件指针读取字符的使用情况总是会遇到各种奇奇怪怪的问题,有时候莫名多出一个空格或者一个空行,后来慢慢接触的多了,才发现这其中的原理,会涉及到输入和输出流的一些问题,现在深刻的觉得要学好哪怕是一件很小的事情,我们都要抱着深入钻研的精神。下午差不多花了两个多小时的时间来了解feof的使用情况,现做如下的总结。

一.feof介绍:

1.在stdio.h中的宏定义

#define  _IOEOF  0x0010 
#define  feof(_stream)  ((_stream)->_flag & _IOEOF)

2.feof的使用:

feof用检测流上的文件结束符,其返回值有两种情况:如果遇到文件结束,函数值为非零值,否则函数值为0。

注:此处的文件结束标志是EOF,EOF的16进制代码为0xFF(十进制为-1),特用在文本文件中,因为在文本文件中数据是以ASCⅡ代码值的形式存放,普通字符的ASCⅡ代码的范围是32到127(十进制),与EOF不冲突,因此可以直接使用。但是在二进制文件中,数据有可能出现-1,因此不能用EOF来作为二进制文件的结束标志,可以通过feof函数来判断。

3.feof的工作原理:

关于这个原理介绍,网上看到了好多资料,其中一个的解释最为形象,易于理解,特在此地引用,后文会推荐那位博主的博客链接,可以看一下正版的东西。

在C语言中有feof()函数,在数据库中有eof()函数,二者作用一样,但是运作方式确实完全不同的。在数据库中,eof()函数的使用符合我们的直观感受,它是读取指针当前的位置,如果指针处于最后一个字符的位置,就知道文件结束了,举个例子,就像你走到了火车的最后一节位置,可知火车到头了。但是在C语言中,feof()函数的使用是根据指针内容判断的,而非指针位置,无论指针是否到头,甚至超出了,它都需要先读取指针的内容,看一看内容是否是EOF,然后才知道文件到头了,同样在之前的例子中,你走到了最后一节的,但是由于最后一节仍有乘客,所以你会判断火车没有到头,你继续向前走,直到下了火车,站在轨道上,没有一个乘客,所以你知道火车到头了。因此,就会出现一些奇怪的现象,我们的目标文档中总会比源文档多出一些,有时候可能是最后字符重复一遍的问题。

二.feof实例分析:

接下来,根据几个小的实例代码来直观的分析feof的工作原理。在此,我以文件读取为例,从test中读取数据,然后根据不同大读取方式来分析结果。

test.txt:

1 2 3              注意:文档中1,2,3之间有一个空格,在3之后没有空行。

常见错误代码:

Code1.

char ch;

while(!feof(fp))

{

ch=fgetc(fp);

printf("%c",ch);

}

实验结果:

分析:

刚才特地提到,在文本中3之后已经结束,但是这里的输出结果中莫名多了一个不可见的字符,然后我们来探究一下这个字符是什么。

修改代码:  printf("%c",ch); -----> printf("%d*",ch); 输出每个字符的值,得到:

通过对比,我们看到最后的字符值是-1,也就是刚才提到的EOF。也许此刻你会想,既然是EOF,为什么把文件结束标志输出来了,不是已经增加了判断!feof(fp)?现在你可以回想一下之前在文章开始的介绍,我们说过feof并不是真正的结束,它需要遇到EOF时才会变成正值,此刻才是结束,也就是说,feof需要在读出EOF之后,才知道文件结束了,现在我们把feof的返回值输出来看一下它是在什么时候变值的。

通过对比,我们看到,在读取最后一个字符3后,feof()的返回值是0,此时while()条件成立,然后继续向文件后读,读出文件结束标志EOF,此刻feof()的返回值变位16,while()条件不满足,因此不再继续,但是由于读出了最后一个EOF,按照代码的要求,读一个马上输出来,因此要输出来,就出现了上文的多出来一个字符情况。

Code2.

如果将上述代码中 ch=fgetc(fp);--->fscanf(fp,"%c",&c);,即使用fscanf函数,出现如下结果:

同样的,此时把最后一个字符重复输出了,我们继续查看一下feof的值变化情况.

和上面的分析情况相似,至于为什么最后一个字符输出的是3,而不是上面的EOF ,这就是fscanf的使用问题了,关于fscanf在遇到EOF时,应经不能读入有效字符了,但是此时输出流中的字符还是3,因此printf中又输出一遍3。

解决办法:

上述的问题就是我们常见的多输出问题,那么该怎么样解决这些问题呢,我在此提出两种解决办法。

Code3:

char c;

c=fgetc(fp);

while(!feof(fp))

{

printf("%c",c);

c=fgetc(fp);

}

这种解决办法只是写法上的巧妙变化,在1和2中,我们倾向于现在读入,现在输出,在3中我们提出一种新的思想,先读入,然后判断此时的指针位置是否合法,在合法的情况下输出上一次读入的值,然后在读取下一个,也就是先读然后判断最后输出的模式,我们每次输出的是上次的字符,因此在最后一个不合法的位置,我们输出了最后一个字符,之后就不会继续循环了。实验结果如下:

Code4:

如果你读取函数是要按照整型读取时,并且文件的结尾存在换行时,我们也可以采用fscanf的方式来判断是否读到文件结尾。如下代码:

int c;

while((fscanf(fp,"%d",&c))==1)    // while((fscanf(fp,"%d",&c))!=EOF)

{

printf("%d-",c);

}

这种解决办法采用的是利用fscanf的返回值来判断文件是否结束,关于fscanf的返回值是:fscanf返回的是实际读取的数据个数,出错或者到结尾返回EOF。在读取最后一个字符时,fscanf不能读到有效字符,因此结果将会返回EOF,自然不会进入whie循环中,整体思路是先判断读到的字符是否合法,然后才输出。实验结果如下:

5.补充:我在4中特意提到了文件结尾存在换行,现提出一种很奇怪的现象。

5.1在处理整型数据时,文件结尾没有换行,即使按照1和2的错误方式写,也不存在上述的多读问题,如下:

int c;

while(!feof(fp))

{

fscanf(fp,"%d",&c);

printf("%d-",c);

}

实验结果如下:

5.2如果我将test.txt中的问价稍作改变,在1 2 3后加上换行,就会出现多读问题,测试结果如下:

针对5中的现象,现在我还没有理解具体是什么原因造成的,以后等到学会时在继续写吧。

关于C语言中feof的使用相关推荐

  1. c语言feof函数_使用示例的C语言中的feof()函数

    c语言feof函数 C语言中的feof()函数 (feof() function in C) Prototype: 原型: int feof(FILE* filename); Parameters: ...

  2. c++freopen函数_使用示例的C语言中的freopen()函数

    c++freopen函数 C语言中的freopen()函数 (freopen() function in C) Prototype: 原型: FILE* freopen(const char *str ...

  3. putc函数_C语言中的putc()函数与示例

    putc函数 C语言中的putc()函数 (putc() function in C) The putc() function is defined in the <stdio.h> he ...

  4. c语言中rewind函数_C语言中的rewind()函数与示例

    c语言中rewind函数 C中的rewind()函数 (rewind() function in C) The rewind() function is defined in the <stdi ...

  5. C语言中scanf与分隔符(空格回车Tab)

    众所周知,C语言中的scanf函数的作用是从标准输入设备(通常是键盘)读取输入值,并存储到参数列表中指针所指向的内存单元.下面从几个方面说一下一些稍微细节的东西.下面的实验都在vc6.0中通过. 1. ...

  6. c语言scanf中的分隔符的作用,C语言中scanf与分隔符(空格回车Tab)

    众所周知,C语言中的scanf函数的作用是从标准输入设备(通常是键盘)读取输入值,并存储到参数列表中指针所指向的内存单元.下面从几个方面说一下一些稍微细节的东西.下面的实验都在vc6.0中通过. 1. ...

  7. c语言中switch语句流程图_全国计算机二级知识点汇总(C语言等)

    点击蓝字 关注我们 全国计算机二级知识点汇总 算法的有穷性是指:算法程序的运行时间是有限的 算法的空间复杂度是指:算法在执行过程中所需要的临时工作单元数 算法的时间复杂度是指:算法在执行过程中所需要的 ...

  8. C语言中fscanf的作用,C语言中fgets和fscanf区别详解

    搜索热词 C语言中fgets和fscanf区别详解 一.作用上的大概区别: ①fgets:从文件中读取一行数据存入缓冲区(fgets遇到回车才会结束,不对空格和回车做任何转换就录入到缓冲区,结束后再往 ...

  9. c语言中的fscanf是啥意思,详解C语言中fgets和fscanf区别

    fscanf函数是C语言的文件格式读取函数的方法之一,它使用空格.制表符和回车来分割不同的单词,这样可以让我们使用起来更方便,下面就让爱站技术频道小编带你来学习详解C语言中fgets和fscanf区别 ...

最新文章

  1. ZYNQ 的三种GPIO :MIO EMIO AXI_GPIO
  2. SpringMVC的Controller方法返回值
  3. 微信接口开发-初级体验
  4. 使用EndNote X9引用参考文献并在Word中修改生成的引文格式(编号、字体大小)GBT7714(numeric)
  5. 用PaddlePaddle(飞桨)实现minist数据集的GAN生成
  6. python自动化笔记_python自动化学习笔记(一)
  7. No package ‘glib-2.0‘ found/No package ‘gobject-2.0‘ found
  8. Julia: 关于Array排序函数sortslices
  9. Win11系统开启控制面板会闪退怎么解决?
  10. Codeforces Gym 100015A Another Rock-Paper-Scissors Problem 找规律
  11. struck的用法c语言,求struck结构体定义和赋值的具体讲解
  12. 树莓派搭建LAMP和FTP服务器
  13. CMake windows下代理设置
  14. 【基于人脸特征的心率检测研究】非接触式光电容积图和红外人脸视频瞬时心率估计
  15. Android 跳转电话、邮件、短信等系统页面
  16. python爬取去哪里_详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?
  17. 【论文阅读】Underwater Image Enhancement: Using Wavelength Compensation and Image Dehazing(WCID)
  18. wordpress美化插件
  19. 树莓派与嵌入式开发的关系
  20. 解决eclipse的 Invalid project description. overlaps the location of another project: 问题

热门文章

  1. CSS 与 地图可视化 三棱锥 (九)
  2. 行之有效:第一章观后有感
  3. 爬取拉钩 破解拉钩反爬机制
  4. google pixel 手机使用magisk获取root权限
  5. 《数字集成电路物理设计——陈春章》学习笔记
  6. 考拉解析公众号解析视频iPhone借助Documents保存视频
  7. Python+Selenium2(上)
  8. 使用了flink官方示例,尽然提交任务后报错了
  9. python爬虫获取百度贴吧内容
  10. historic historical