EOF
它是end of file的缩写,表示"文字流"(stream)的结尾。
这里的"文字流",可以是文件(file),也可以是标准输入(stdin)。
键盘怎么输入:
Linux中,在新的一行的开头,按下Ctrl-D,就代表EOF
(如果在一行的中间按下Ctrl-D,则表示输出"标准输入"的缓存区,所以这时必须按两次Ctrl-D);
Windows中,Ctrl-Z表示EOF。(by the way,Linux中按下Ctrl-Z,表示将该进程中断,在后台挂起,用fg命令可以重新切回到前台;按下Ctrl-C表示终止该进程。)
如果真的想输入Ctrl-D:先按下Ctrl-V,然后输入Ctrl-D,系统就不会认为这是EOF信号。
Ctrl-V表示:按"字面含义"解读下一个输入,要是想按"字面含义"输入Ctrl-V,连续输入两次就行了。
代码教训:
错误:
while(scanf("%c",&c),c!=EOF)
正确:
while(c=getchar(),c!=EOF)
while(scanf("%c",&c)!=EOF)
while(scanf("%d",&c)!=EOF)
原因:
scanf("%c",&c)是有一个返回值的,无法获取EOF
查阅(源自网络):在大师编写C的时候,当时并没有所谓终端输入的概念,所有的输入实际上都是按照文件进行读取的,文件中一般都是以行为单位的。因此,只有遇到换行符,那么程序会认为输入结束,然后采取执行程序的其他部分。同时,输入是按照文件的方式存取的,那么要结束一个文件的输入就需用到EOF(Enf Of File). 这也就是为什么getchar结束输入退出时要用EOF的原因。
问题:EOF是怎么起作用的
错误认知:每个文件的结尾处,有一个叫做EOF的特殊字符,读取到这个字符,操作系统就认为文件结束了。
正确认知:EOF不是特殊字符,而是一个定义在头文件stdio.h的常量,一般等于-1。即: #define EOF (-1)
问题:如果EOF是一个特殊字符,那么假定每个文本文件的结尾都有一个EOF(也就是-1),还是可以做到的,因为文本对应的ASCII码都是正值,不可能有负值。但是,二进制文件怎么办呢?怎么处理文件内部包含的-1呢?
答案:在Linux系统之中,EOF根本不是一个字符,而是当系统读取到文件结尾,所返回的一个信号值(也就是-1)。
问题:系统怎么知道文件的结尾?
错误理解:
当文件结尾读取到EOF的时候就结束操作。
正确理解:
在fgetc函数内部,每次都是读取一个字节的数据,而且这一个字节的数据是以unsigned即无符号型处理的,然后将这一个字节的数据赋给一个int型变量作为返回值返回,因此无论从文件中读取的是什么数据,作为无符号型赋值给一个int型变量,返回值不可能是负数。比如当读取到数据0xFA时,因为是以无符号处理的,因此在将0xFA赋值给int型变量的时,int型变量的高位是填充0的(为什么填充0,跟汇编语言里面的符号扩展类似,在后面会提到),因此返回的结果是0X00 00 00 FA,始终不会是负数.而若读取到文件末尾的时候,即没有数据可供读取的时候,那么返回EOF,即-1,这个-1是一个int型常量,二进制表示是0x FF FF FF FF。
举例:
int c;
//注意:为什么不是char c;
while ((c = fgetc(fp)) != EOF) {
do something
}
为什么是int c;
char c; 和 int c; 利弊:
char c;比较局限,int型比较好:
局限:其只能判断是否到达文本文件的末尾,而不能对二进制文件进行准确的判断。
文本文件:正常情况下,文本文件中无法读取到-1(0x FF)这个数据,因此可以判断。
二进制文件:二进制文件中就算不是文件末尾,也可能就会读取到0xFF的数据,此时的返回值就是-1。
二者应用差别举例:
若ch为char型,则当将返回值0x 00 00 00 FF返回时,取低8位赋给ch,那么此时ch为-1,此时会误判为到达文件末尾;
若ch为int 型,则当将返回值0x 00 00 00 FF返回时,ch的值为0x 00 00 00 FF,此时ch不为-1,不会误判为文件末尾。