EOF及相关函数
结论:EOF是在头文件stdio.h中预定义的一个宏,而eof(end of file)是一个与标准输入/输出流相关联的标志位。当文件指针已经指向文件尾且再次尝试读取时,eof标志会被设置。同时,某些函数会在读取到文件尾(即eof标志被设置)时返回EOF作为标识。
另注:
笔者经常会在C进行文件I/O操作时出现文件读取实际尚未结束(未读取至文件末尾),但系统显示已读取至文件尾的情况。具体原因如下。
在过去的操作系统中,文件以文件存储占用的扇区数作为文件大小的计数单位,故而如果文件的大小不能恰好填满存储文件的最后一个扇区,则需要对该扇区剩余的空间进行填充,过去填充使用的是值为26(0x1a)的字节,也就是某些系统中 Ctrl+Z 的对应码值,故而在读取文件过程中,读取到值26,则系统认为文件已经到达末尾,不再读取。在 windows 环境下,终端输入可以使用 Ctrl + z 作为输入的 EOF 标志,而 linux 环境下,则可使用 Ctrl + d 作为输入的结束标志。
现在的操作系统开始使用字节作为文件大小的计数单位,但古老的习惯还是被保留下来。为了避免文件读取过程中存在值为26的数据使得系统误认为文件结束而停止读取,可以将文件以二进制文件格式打开。
EOF
EOF常被在程序中用于判断(文件)缓冲区是否结束,实际在头文件 stdio.h 中定义。

可以看到EOF是一个头文件中预定义的宏,其值为 -1 。也就是说,在程序中使用的EOF实际为一个预定义的常数。而许多的函数会在读取至文件末尾或出现错误时,会返回EOF,作为处理状态的一种描述,如下文的getchar.
getchar(getchar C++ Reference)
函数声明:int getchar(void);
函数功能:当函数读取成功时,会返回成功读取的字符数据(转化为 int 类型),若失败,则返回值为EOF,也就是上文说的值为 -1 的宏定义。

可以从上面的介绍中看到,函数除返回EOF外,还会设置标准输入( stdin )的 eof 标志/error标志,可供feof或ferror函数使用。也就是说,EOF(宏定义)与eof标志并不是同一个东西。
getchar函数在头文件stdio.h中定义,具体实现如下:

显然,读取字符数据并指向下一个待读取的数据操作是由 *stdin->_ptr++ 来实现的,而返回 EOF 以及将上文提及的error标志和eof标志则是由函数_filbuf实现。
从上面资料可以得到结论:
(1)对一般的文件/输入流,存在一个指向待读取数据位置的内部的指针(如上面的stdin->_ptr),每次读取数据完成该内部指针会移动指向下一个待读取数据;
(2)文件/输入流还存在两个特殊的标志 eof 和 error ,它们可以分别被函数feof和ferror处理,当文件读取至文件末尾或出现错误时,相应的标志位eof/error会被设置;
(3)一些函数在发生错误或读取至文件末尾时,会返回EOF,其为值为 -1 的宏,同时设置文件/输入流的某些标志;
feof( feof C++ Reference)
函数声明:int feof(FILE *stream); //stream为对应的文件流的标志
函数功能:会检查与文件对应流的eof( end of file )标志是否被设置,如果被设置则返回非零值,如未被设置,则返回0.
注意:feof函数只检查eof标志是否被设置,其本身并不会设置eof标志,设置eof标志的是试图进行数据读取的操作。
示例:
#include<stdio.h> int main(void)
{
FILE *ptr = fopen("a.txt","r"); if(!ptr)
{
printf("打开文件失败!\n");
return -;
} char ch;
int count = ; while(!feof(ptr)) //检测到EOF标志则停止
{
count++;
ch = fgetc(ptr);
printf("%c",ch);
}
printf("%5d",count);
printf("\n"); fclose(ptr);
return ;
}
示例代码读取的a.txt的内容为"12".代码会逐字节显示文件的内容(19、20行),以及读取的次数(18、22行)。
执行结果下图所示:

(1)EOF标志未被设置时,feof函数会返回0,eof标志被设置后,feof返回非零值;
(2)每次读取成功后,指向文件流内部的指针会顺序移动读取的字数个字节(对文本来说),这样使得内部指针总是指向待读取的下一个字符;
(3)执行流程 : feof返回值为0,第一次循环,ch = ‘1’,count = 1,流内部的位置指针指向‘2’;feof返回值为0,第二次循环,ch = ‘2’,count = 2,流内部的位置指针指向文件末尾,但此时EOF并未被设置;feof返回值仍为0,第三次循环,会试图访问文件的末尾,count = 3,eof 标志被设置,下一次的feof返回值为非0值,故而结束循环;(笔者在CodeBlocks12.13中调试时,第三次循环时ch的值为-1,即为EOF,printf并没有将其显示至控制台)
文件流内部存在标志读取位置的内部指针,该位置指针指向文件尾并不会设置对应文件流的eof 标志,只有当该位置指针指向文件尾,并再次试图进行顺序读操作时,才会设置eof标志。
EOF为一个定义的宏常量,而eof标志为与文件/输入流相关的一个标志,当位置指针已指向文件末尾并再次试图读取输入时,会设置eof标志,同时为了表明发生的情况,函数一般会返回EOF用来表示文件读取至末尾或发生错误。
EOF及相关函数的更多相关文章
- fopen()及相关函数使用
函数简介 函数功能:打开一个文件 函数原型:FILE * fopen(const char * path,const char * mode); ],_wfopen 所需库:<stdio.h&g ...
- 学习PHP中的iconv扩展相关函数
想必 iconv 这个扩展的相关函数大家多少都接触过,做为 PHP 的默认扩展它已经存在了很久,也是我们在操作字符编码时经常会使用的函数.不过除了 iconv() 这个函数外,你还知道它的其它函数吗? ...
- linux下EOF写法梳理
在平时的运维工作中,我们经常会碰到这样一个场景:执行脚本的时候,需要往一个文件里自动输入N行内容.如果是少数的几行内容,还可以用echo追加方式,但如果是很多行,那么单纯用echo追加的方式就显得愚蠢 ...
- php定界符<<<EOF讲解(转)
Heredoc技术.可用来输出大段的html和javascript脚本 1.PHP定界符的作用就是按照原样,包括换行格式什么的,输出在其内部的东西: 2.在PHP定界符中的任何特殊字符都不需要转义: ...
- while(cin.eof)出错 poj
zoj遇到c++如何判定输入流结尾的问题,一不小心就超时了 楼下的代码可以通过zoj #include<iostream> using namespace std; int main(){ ...
- c++ eof()函数
C++ eof()函数可以帮助我们用来判断文件是否为空,抑或是判断其是否读到文件结尾.在这里我们将会对其进行详细的介绍. C++编程语言中的很多功能在我们的实际应用中起着非常大的作用.比如在对文件文本 ...
- 【转】 解读EOF
解读EOF 标签: fplinuxc语言filestream 2012-01-31 22:05 439人阅读 评论(0) 收藏 举报 分类: C.C++_程序设计(20) 我学习C语言的时候,遇到 ...
- Linux C 字符函数 getchar()、putchar() 与 EOF 详解
首先给出<The_C_Programming_Language>这本书中的例子: #include <stdio.h> int main() { int c; c = getc ...
- Ext3文件系统mount选项和文件属性介绍
mount选项 设置方式 ext3 mount选项可以通过多个方式进行设置:1)内核编译时: 内核menuconfig通过CONFIG_EXT3_DEFAULTS_TO_ORDERED编译控制选项,来 ...
随机推荐
- java爬取百度首页源代码
爬虫感觉挺有意思的,写一个最简单的抓取百度首页html代码的程序.虽然简单了一点,后期会加深的. package test; import java.io.BufferedReader; import ...
- first post
post
- 一:Nginx知识整理
Nginx与服务器集群 一:集群 1.什么是集群 集 合在一起 放在一起 群 一堆 很多 服务器架构集群:多台服务器组成的响应大并发,高数据量访问的架构体系. 分布式服务器架构: 特点: 1)成本高 ...
- c# 获取文件夹大小
private long GetDirectorySizeMethod1(string directory) { long directorySize = 0; DirectoryInfo di = ...
- tmux使用技巧
1.tmux 进入tmux 2.在tmux中 按ctrl+b 表示要进行tmux操作了. 3. c -> create a session 4. "," -> ren ...
- PAT 1071. Speech Patterns
又是考输入输出 #include <cstdio> #include <cstdlib> #include <string> #include <vector ...
- 解决vue移动端适配问题
1,先看看网上关于移动端适配讲解 再聊移动端页面适配,rem和vw适配方案! 基础点:rem相对根节点字体的大小.所以不用px; 根字体:字体的大小px; px:你就当成cm(厘米)这样的东西吧: 基 ...
- JavaEE之HttpServletResponse
HttpServletResponse概述 我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和代表响应r ...
- 原生JS编写getByClass、addClass、removeClass、hasClass
前言: 年后换了工作,在现在的公司写交互主要使用JS原生:刚刚入门前端的时候写交互一直用的原生JS,虽然用的不怎么样.后来去之前的公司之后,leader主张把jQuery用好,JS原生自然就熟练了:一 ...
- git日常使用
git强制回滚指定版本git reset --hard xxx(版本名) git强制推送git push -f remote(远程地址) branch(远程分支) 查看远程分支 git branch ...