关于EOF,转自新浪微博

  本文转自http://blog.sina.com.cn/s/blog_7714171f0101798y.html

     
EOF 是 End Of File 的缩写。

在C语言中,它是在标准库中定义的一个宏。

人们经常误认为 EOF 是从文件中读取的一个字符(牢记)。其实,EOF 不是一个字符,它被定义为是 int 类型的一个负数(比如 -1)。EOF 也不是文件中实际存在的内容。EOF 也不是只表示读文件到了结尾这一状态(这种状态可以用 feof() 来检测),它还能表示 I/O 操作中的读、写错误(通常可以用 ferror() 来检测)以及其它一些关联操作的错误状态。

一、getchar的两点总结:
1.getchar是以行为单位进行存取的。
当用getchar进行输入时,如果输入的第一个字符为有效字符(即输入不是文件结束符EOF,Windows下为组合键 Ctrl+Z,Unix/Linux下为组合键Ctrl+D),那么只有当最后一个输入字符为换行符'/n'(也可以是文件结束符EOF,EOF将在后面 讨论)时,getchar才会停止执行,整个程序将会往下执行。譬如下面程序段:

 

while((c =getchar())!=EOF){
    putchar(c);
}

 


执行程序,输入:abc,然后回车。则程序就会去执行puchar(c),然后输出abc,这个地方不要忘了,系统输出的还有一个回车。然后可以继续输入,再次遇到换行符的时候,程序又会把那一行的输入的字符输出在终端上。

对于getchar,肯定很多初学的朋友会问,getchar不是以字符为单位读取的吗?那么,既然我输入了第一个字符a,肯定满足while循环(c = getchar()) != EOF的条件阿,那么应该执行putchar(c)在终端输出一个字符a。不错,我在用getchar的时候也是一直这么想的,但是程序就偏偏不着样执 行,而是必需读到一个换行符或者文件结束符EOF才进行一次输出。对这个问题的一个解释是,在大师编写C的时候,当时并没有所谓终端输入的概念,所有的输 入实际上都是按照文件进行读取的,文件中一般都是以行为单位的。因此,只有遇到换行符,那么程序会认为输入结束,然后采取执行程序的其他部分。同时,输入 是按照文件的方式存取的,那么要结束一个文件的输入就需用到EOF(Enf Of File). 这也就是为什么getchar结束输入退出时要用EOF的原因。
2.getchar()的返回值一般情况下是字符,但也可能是负值,即返回EOF。

这里要强调的一点就是,getchar函数通常返回终端所输入的字符,这些字符系统中对应的ASCII值都是非负的。因此,很多时候,我们会写这样的两行代码:

 

char c;
c =getchar();

 



这样就很有可能出现问题。因为getchar函数除了返回终端输入的字符外,在遇到Ctrl+D(Linux下)即文件结束符EOF 时,getchar()的返回EOF,这个EOF在函数库里一般定义为-1。因此,在这种情况下,getchar函数返回一个负值,把一个负值赋给一个 char型的变量是不正确的。为了能够让所定义的变量能够包含getchar函数返回的所有可能的值,正确的定义方法如下(K&R C中特别提到了这个问题):

 

int c;
c =getchar();

 

二、EOF的两点总结(主要指普通终端中的EOF)
1.EOF作为文件结束符时的情况:

EOF虽然是文件结束符,但并不是在任何情况下输入Ctrl+D(Windows下Ctrl+Z)都能够实现文件结束的功能,只有在下列的条件下,才作为文件结束符。
(1)遇到getcahr函数执行时,要输入第一个字符时就直接输入Ctrl+D,就可以跳出getchar(),去执行程序的其他部分;
(2)在前面输入的字符为换行符时,接着输入Ctrl+D;
(3)在前面有字符输入且不为换行符时,要连着输入两次Ctrl+D,这时第二次输入的Ctrl+D起到文件结束符的功能,至于第一次的Ctrl+D的作用将在下面介绍。
其实,这三种情况都可以总结为只有在getchar()提示新的一次输入时,直接输入Ctrl+D才相当于文件结束符。

2.EOF作为行结束符时的情况,这时候输入Ctrl+D并不能结束getchar(),而只能引发getchar()提示下一轮的输入。

这种情况主要是在进行getchar()新的一行输入时,当输入了若干字符(不能包含换行符)之后,直接输入Ctrl+D,此时的Ctrl+D并不是文件 结束符,而只是相当于换行符的功能,即结束当前的输入。以上面的代码段为例,如果执行时输入abc,然后Ctrl+D,程序输出结果为:
abcabc

注意:第一组abc为从终端输入的,然后输入Ctrl+D,就输出第二组abc,同时光标停在第二组字符的c后面,然后可以进行新一次的输入。这时如果再次输入Ctrl+D,则起到了文件结束符的作用,结束getchar()。
如果输入abc之后,然后回车,输入换行符的话,则终端显示为:
abc         //第一行,带回车
abc         //第二行
               //第三行

其中第一行为终端输入,第二行为终端输出,光标停在了第三行处,等待新一次的终端输入。
从这里也可以看出Ctrl+D和换行符分别作为行结束符时,输出的不同结果。
EOF的作用也可以总结为:当终端有字符输入时,Ctrl+D产生的EOF相当于结束本行的输入,将引起getchar()新一轮的输入;当终端没有字符 输入或者可以说当getchar()读取新的一次输入时,输入Ctrl+D,此时产生的EOF相当于文件结束符,程序将结束getchar()的执行。

 

【补充】本文第二部分中关于EOF的总结部分,适用于终端驱动处于一次一行的模式下。也就是虽然getchar()和putchar()确实是按照每次一个字符 进行的。但是终端驱动处于一次一行的模式,它的输入只有到“/n”或者EOF时才结束,因此,终端上得到的输出也都是按行的。
如果要实现终端在读一个字符就结束输入的话,下面的程序是一种实现的方法(参考《C专家编程》,略有改动)


#include
#include

int
main(void)
{
    int c;
   
    system("stty raw");
   
   
    c =getchar();
    putchar();
   
   
     system("stty cooked");
   
    return 0;
}


编译运行该程序,则当如入一个字符时,直接出处一个字符,然后程序结束。
由此可见,由于终端驱动的模式不同,造成了getchar()输入结束的条件不一样。普通模式下需要回车或者EOF,而在一次一个字符的模式下,则输入一个字符之后就结束了。

 


(1) 字节的读取
在正常的情况下, getc 以 unsigned char 的方式读取文件流, 扩张为一个整数,并返
回. 换言之, getc 从文件流中取一个字节, 并加上24个零,成为一个小于256的整数,
然后返回.

int c;
while ((c = fgetc (rfp))!= -1) // -1就是 EOF
fputc (c, wfp);

上面 fputc 中的 c 虽然是整数, 但在 fputc 将其写入文件流之前, 又把整数的高24位
去掉了, 因此 fgetc, putc 配合能够实现文件复制. 到目前为止, 把 c 定义为
char仍然是可行的, 但下面我们将看到,把 c 定义为 int 是为正确判段文件是否结束.

(2) 判断文件结束.

多数人认为文件中有一个EOF,用于表示文件的结尾. 但这个观点实际上是错误的,在文
件所包含的数据中,并没有什么文件结束符. 对getc 而言, 如果不能从文件中读取,
则返回一个整数 -1,这就是所谓的EOF. 返回 EOF 无非是出现了两种情况,一是文件已
经读完; 二是文件读取出错,反正是读不下去了.

请注意: 在正常读取的情况下, 返回的整数均小于256, 即0x0~0xFF. 而读不出返回的
是 0xFFFFFFFF. 但, 假如你用fputc把 0xFFFFFFFF 往文件里头写, 高24位被屏蔽,写入的将
是 0xFF. // lixforalpha 请注意这一点

(3) 0xFF 会使我们混淆吗?

不会, 前提是, 接收返回值的 c 要按原型定义为 int.

如果下一个读取的字符将为 0xFF, 则

int c;
c = fgetc (rfp); // c = 0x000000FF;
if (c != -1)    // 当然不等, -1 是 0xFFFFFFFF
fputc (wfp);   // 噢, OXFF 复制成功.

字符0xFF, 其本身并不是EOF.

(4) 将 c 定义 char

假定下一个读取的字符为 0xFF 则

char c;
c = fgetc (rfp); // fgetc(rfp)的值为 0x000000FF, 暗中降为字节, c = 0xFF
if (c != -1)    // 字符与整数比较? c 被带符号(signed)扩展为0xFFFFFFFF, 喔噢,
条件成立,文件复制提前退出.

while ((c=fgetc(rfp))!=EOF) 中的判别条件成立, 文件复制结束! 意外中止.

(5) 将 c 定义为 unsigned char;

当读到文件末尾, 返回 EOF 也就是 -1 时,

unsigned char c;
c = fgetc (rfp); // fgetc (rfp)的值为EOF,即-1,即0xFFFFFFFF, 降格为字节, c=0xFF
if ( c!= -1)  // c 被扩展为 0x000000FF, 永远不回等于 0xFFFFFFFF

所以这次虽然能正确复制 0xFF, 但却不能判断文件结束. 事实上,在 c 为 uchar 时,
c != -1 是永远成立的, 一个高质量的编译器, 比如 gcc会在编译时指出这一点.

(6) 为何需要feof?
FILE *fp;
fp 指向一个很复杂的数据结构, feof 是通过这个结构中的标志来判断文件是否结束的.
如果文件用 fgetc 读取, 刚好把最后一个字符读出时, fp 中的EOF标志不会打开,这时
用feof判断,将会得到文件尚未结束的结论.

fgetc 返回 -1 时, 我们仍无法确信文件已经结束, 因为可能是读取错误! 这时我们
需要 feof 和 ferror.

 

 

总结:EOF并不是存在于文件中的,而是一种状态,当读到文件末尾或者读取出错时就会返回这个值来判断文件结束。(即即使读取错误可能也被认为文件结束,所以就需要用feof 和 ferror来判断是不是真的文件结束了)

当用getchar(c)时,即使c定义成字符型,也可以结束,主要是c与-1比较时,c也会从char转换为整型值。

写个小程序验证了一下

 

[cpp] view plaincopyprint?

  1. #include    
  2. int main()  
  3. {  
  4.   char c;  
  5.   c = -1;  
  6.   printf("%x",c);  
  7.   return 0;  
  8. }  

 

转载于:https://www.cnblogs.com/jkred369/p/3603063.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493394.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

100年前没人信他,但他仅1项研究便远程摧毁万架飞机……

来源:世界科技创新论坛摘要:他是爱迪生最强大的对手,也是一个一生独立开发并取得专利700种,合作开发达1000种以上的科学狂人。科学界有一个普遍共识,人类历史上曾经存在过两个公认的旷世天才:达芬奇和尼古拉…

服务器安装opencv报错--libSM.so.6: cannot open shared ...+tensorflow 报错libcusolver.so.8.0: can not...

1.安装opencv出现以下错误: pip install opencv-contrib-python apt-get install -y python-qt4 apt-get install tk-dev python-tk 例如linux.zip.001, linux.zip.002, linux.zip.003... 首先 cat linux.zip* > linux.zip #合并为一个zip包 然后 unzip linu…

将JSON转成DataSet(DataTable)

方法1&#xff1a; /// <summary>/// 将JSON解析成DataSet只限标准的JSON数据/// 例如&#xff1a;Json&#xff1d;{t1:[{name:数据name,type:数据type}]} /// 或 Json&#xff1d;{t1:[{name:数据name,type:数据type}],t2:[{id:数据id,gx:数据gx,val:数据val}]}/// <…

AlphaGo之后,DeepMind重磅推出AlphaFold:基因序列预测蛋白质结构

来源&#xff1a;机器之心摘要&#xff1a;Alphabet&#xff08;谷歌&#xff09;旗下公司 DeepMind 的人工智能 AlphaGo 曾在国际象棋、围棋等项目中取得了超越人类的表现&#xff0c;其研究不仅震惊世界&#xff0c;也两次登上 Nature。如今&#xff0c;该公司已将人工智能技…

Web开发之容器

Web开发之容器 主题 Servlet容器、Web容器、应用服务器 参考资料 Servlet容器、Web容器、应用服务器 Servlet容器的主要任务是管理Servlet的生命周期&#xff1b;而Web容器更准确的说应该叫做Web服务器&#xff0c;它是用来管理和部署Web应用的&#xff1b;还有一种服务器叫做应…

李开复看2019投资趋势:最坏的时代将酝酿最伟大的公司

来源&#xff1a;网易智能摘要&#xff1a;12月3日下午&#xff0c;创新工场在北京举办了2019投资趋势分享会。创新工场创始人、董事长兼CEO李开复&#xff0c;创新工场联合创始人、管理合伙人汪华与创新工场合伙人张鹰对目前中国经济形势和投资趋势做了分析。01最坏的时代将酝…

高斯混合模型做聚类

概述 聚类算法大多数采用相似度来判断&#xff0c;而相似度又大多数采用欧式距离长短来衡量&#xff0c;而GMM采用了新的判断依据—–概率&#xff0c;即通过属于某一类的概率大小来判断最终的归属类别 。 GMM的基本思想就是&#xff1a;任意形状的概率分布都可以用多个高斯分…

C#使用HTML文件中的file文件上传,用C#代码接收上传文件

单独做图片上传很简单&#xff0c;如果要客户端要上传头像保存到服务器就要稍微麻烦一点点了。 不多说了&#xff0c;直接上源码&#xff1a; private void Upload() { string jsonInfo string.Empty; ///这句是关键&#xff0c;它是获取HTTP中文件流 的对象集合。 Ht…

基于深度学习的NLP 32页最新进展综述,190篇参考文献

来源&#xff1a;专知摘要&#xff1a;深度学习使用多层学习层次的数据表示,并在许多领域得到了最优的结果。最近,各种各样的模型设计和方法在自然语言处理(NLP)蓬勃发展。在本文中,我们回顾了被广泛应用于各种NLP任务的深度学习相关模型和算法以及它们的发展演变过程。我们还总…

.net framework摘抄与理解

1."源码"编译成"托管模块": 2.将"托管模块"合并成"托管程序集" 3.clr中的"JIT"执行"托管程序集" 第二次执行已被JIT编译成机器码的Console.WriteLine("") 转载于:https://www.cnblogs.com/doujiaomifan…

“新一代人工智能前沿与挑战”国际研讨会专家观点分享

来源&#xff1a;西电人工智能学院摘要&#xff1a;2018年11月25日-26日举办的“新一代人工智能前沿与挑战”中青年论坛暨第二十一届学术周在西安电子科技大学圆满落幕&#xff0c;研讨会上包括长江学者、IEEE Fellow、领域顶尖中青年学者、新锐企业领导者等在内的国内外权威专…

决策树算法及可视化

经典决策树算法包括ID3算法、C4.5算法以及GBDT的基分类器CART算法 ,ID3算法选择特征的依据是信息增益、C4.5是信息增益比&#xff0c;而CART则是Gini指数。 例子: 所谓信息增益就是数据在得到特征X的信息时使得类Y的信息不确定性减少的程度。假设数据集D的信息熵为H(D)&#x…

ListView排序并隔色显示

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Windows.Forms; using System.Drawing;namespace STools {class ListViewColumnSorter : IComparer{/**//// <summary>/// 指定按照哪个…

python多进程并发+pool多线程+共享变量

一&#xff0e;多进程 当计算机运行程序时&#xff0c;就会创建包含代码和状态的进程。这些进程会通过计算机的一个或多个CPU执行。不过&#xff0c;同一时刻每个CPU只会执行一个进程&#xff0c;然后不同进程间快速切换&#xff0c;给我们一种错觉&#xff0c;感觉好像多个程…

高通骁龙855发布,5G大幕拉开,新一轮手机大战在即

来源&#xff1a;网易智能摘要&#xff1a;高通终于公布下一代移动芯片骁龙855。美国时间12月4日&#xff0c;高通在美国夏威夷召开了第三届高通骁龙技术峰会&#xff0c;在峰会首日&#xff0c;骁龙855正式发布。并非外界传言的8150&#xff0c;高通还是沿用了之前的命名规则。…

机器学习的几种方法(knn,逻辑回归,SVM,决策树,随机森林,极限随机树,集成学习,Adaboost,GBDT)

一.判别模式与生成模型基础知识 举例&#xff1a;要确定一个瓜是好瓜还是坏瓜&#xff0c;用判别模型的方法是从历史数据中学习到模型&#xff0c;然后通过提取这个瓜的特征来预测出这只瓜是好瓜的概率&#xff0c;是坏瓜的概率。 举例&#xff1a;利用生成模型是根据好瓜的特…

大端小端模式

大端小端模式是指内存中的数据存储方式。 大端模式&#xff0c;指数据的高位字节存在内存的低地址&#xff0c;数据的低位字节存在内存的高地址。 小端模式&#xff0c;指数据的高位字节存在内存的高地址&#xff0c;数据的低位字节存在内存的低地址。 如十六进制数0x12345678&…

京东物联网战略大升级|与华为合作,疯狂发布新品,“养鱼”的京东正在物联网赛道上花式秀技术...

来源&#xff1a;物联网智库12月4日下午&#xff0c;在“智联万物 新响无限”2018年京东IoT战略发布会上&#xff0c;京东发布了其IoT领域的最新战略规划&#xff0c;推出了新的品牌“京鱼座”&#xff0c;还推出一系列合作品牌与硬件产品&#xff0c;该战略不仅是对去年5月9日…

centos下apache安装

安装环境&#xff1a;centos查找可安装的包&#xff1a;yum list httpd*安装&#xff1a;yum install httpd.x86_64查看安装包的所有安装文件&#xff1a;rpm -ql httpd 配置文件&#xff1a;/etc/httpd/conf/httpd.conf日志目录&#xff1a;/etc/httpd/logs页面存放路径&…

电动车的惊世骗局

来源&#xff1a;世界科技创新论坛摘要&#xff1a;新能源是一个很好的机会&#xff0c;技术也没有瓶颈&#xff0c;如果发展对了方向&#xff0c;十年扶持一两个世界领先水平的企业是没问题的。但如果有人趁机“钻空子”&#xff0c;让有限的资源被浪费&#xff0c;怕是很难有…