feof问题
feof()函数是我们C语言中操作文件常见的函数,也是我们最容易出错的函数
这个函数用来表示文件指针是否已经到了文件末尾的下一个位置。这个函数是通用的
可以用在文本文件和二进制文件
(EOF是文件结束的标志:
(但是注意,在文本文件中,判断文本文件在文本文件结束符为不可见字符,值为26)
(二进制中文件结束标志为-1,当把数据以二进制形式存放到文件中时,就会有-1值的出现,因此不能采用EOF作为二进制文件的结束标志)
我们常见的问题时用fgets读文件,然后用fputs打印,这样就会在最后一行出现问题
多输出一遍:
我们看feof在源码中定义:
#define _IOEOF 0x0010 #define feof(_stream) ((_stream)->_flag&_IOEOF)
因此,当file position indicattor(windows fp->_ptr)到了文件末尾,然后再发生读写文件时候,fp->_flags才会被置为含有_IOEOF,然后再调用feof(),才会得到文件结束的信息。
也就是说只有文件指针到了文件末尾的下一个位置,feof才会返回1
例如程序:
while(!feof(fp)) { fgets(str,80,fp); fpets(str,stdout); }
在该程序段中,当我们读到最后一行,这个时候feof返回0,是正确的。
然后接着读取,由于fgets函数读取的时候会判断是否碰到了_IOFOF。此时当然是到了
因此传递给数组的内容还是上一次的,也就是说,最后一次数组没有读取 数据,还是上一次的
,因此就打印两边:
知道这个原理,我们可以巧妙的绕过去这个陷阱,设计循环的时候我们做到先判断,在输出
(fgets和feof判断相继),于是这样我们判断后就不会打印两遍:
fgets(str,80,fp); while(!feof(fp)) { fputs(str,stdout); fgets(str,80,fp); }
当然,如果我们不想这样设计(fgets代码写两遍,感觉不爽),可以改变其他条件
1,用fgetc判断(当然这个不太保险,因为文件出错和结束返回值一样!!!)
while((c = fgetc(fp)) != -1) { fputc(c,fp); }
2,要用fgets判断:遇到文件结束返回NULL
while(fgets(str,80,fp)) { fputs(str,fp) }
getchar()函数 => :#define getchar() getc(stdin)
getchar有一个int型的返回值.当程序调用getchar时.程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符.getchar函数的返回值是用户输入的第一个字符的ASCⅡ码,如出错返回-1,且将用户输入的字符回显到屏幕.如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取.也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键.
有两点行为:
1,getchar是以行为单位就行存取的('\n行刷新),也就是说只有遇到回车换行或者文件结束会结束(Ctrl+z,windows)意思是你的输入必须有行刷新或者文件结束才能有下面的执行
#include <stdio.h> int main() { char c; while((c =getchar())!=EOF) { putchar(c); } return 0; }
对这个问题的一个解释是,并没有所谓终端输入的概念,所有的输入实际上都是按照文件进行读取的,文件中一般都是以行为单位的。因此,只有遇到换行符,那么程序会认为输入结束,然后采取执行程序的其他部分。同时,输入是按照文件的方式存取的,那么要结束一个文件的输入就需用到EOF(Enf Of File). 这也就是为什么getchar结束输入退出时要用EOF的原因
2,getchar()返回字符,或者EOF(文件结束)
因此最后用int类型的来接收返回至,然后用char类型输出
由于getchar行缓冲的作用因此有时候我们要在控制台上进行结束会出现两种情况
Ctrl+z结束(这时是下一次输入提醒)
Ctrl+z,Ctrl+z(这时是一次输入刚结束,没有按行刷新,因此第一个相当于行刷新,第二个相当于文件流结束)