关于EOF的问题

EOF是 end of file的缩写,表示"文字流(" stream)的结尾。这里的"文字流",可以是文件(file),也可以是标准输入(stdin)。
EOF 不是特殊字符,而是一个定义在头文件 stdio.h 的常量,一般等于-1

#define EOF (-1)

除了表示文件结尾,EOF 还可以表示标准输入的结尾。但是,标准输入与文件不一样,无法事先知道输入的长度,必须手动输入一个字符,表示到达 EOF它是 end of file 的缩写,表示"文字流"(stream)的结尾。这里的"文字流",可以是文件(file),也可以是标准输入(stdin)。比如,下面这段代码就表示,如果不是文件结尾,就把文件的内容复制到屏幕上。

int c;
while ((c = fgetc(fp)) != EOF) {
putchar (c);}

很自然地,我就以为,每个文件的结尾处,有一个叫做 EOF 的特殊字符,读取到这个字符,操作系统就认为文件结束了。但是,后来我发现,EOF 不是特殊字符,而是一个定义在头文件 stdio.h 的常量,一般等于-1#define EOF (-1)。于是,我就困惑了。

如果 EOF 是一个特殊字符,那么假定每个文本文件的结尾都有一个 EOF(也就是-1),还是可以做到的,因为文本对应的 ASCII 码都是正值,不可能有负值。但是,二进制文件怎么办呢?怎么处理文件内部包含的-1 呢?

这个问题让我想了很久,后来查了资料才知道,在 Linux 系统之中,EOF 根本不是一个字符,而是当系统读取到文件结尾,所返回 的一个信号值(也就是 -1)。至于系统 怎么知道文件的结尾,资料上说是通过比较文件的长度。

所以处理文件如下:

int c;
while ((c = fgetc(fp)) != EOF) {
    do something
}

这样写有一个问题。fgetc()不仅是遇到文件结尾时返回 EOF,而且当发生错误时,也会返回EOF。因此,C 语言又提供了 feof()函数,用来保证确实是到了文件结尾。上面的代码 feof()版本的写法就是:

int c;
while (!feof(fp)) {
    c = fgetc(fp);
    do something;
}

但是,这样写也有问题。fgetc()读取文件的最后一个字符以后,C 语言的 feof()函数依然返回0,表明没有到达文件结尾;只有当 fgetc()向后再读取一个字符(即越过最后一个字符),feof()才会返回一个非零值,表示到达文件结尾。

所以,按照上面这样写法,如果一个文件含有 n 个字符,那么 while 循环的内部操作会运行n+1 次。所以,最保险的写法是像下面这样:

int c = fgetc(fp);
while (c != EOF) {
    do something;
    c = fgetc(fp);
}
if (feof(fp)) {
    printf("\n End of file reached.");
} else {
    rintf("\n Something went wrong.");
}

除了表示文件结尾,EOF 还可以表示标准输入的结尾。

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

但是,标准输入与文件不一样,无法事先知道输入的长度,必须手 动输入一个字符,表示到达 EOF

Linux 中,在新的一行的开头,按下 Ctrl-D,就代表 EOF(如果在一行的中间按下 Ctrl-D,则表示输出"标准输入"的缓存区,所以这时必须按两次 Ctrl-D);Windows 中,Ctrl-Z 表示 EOF。(顺便提一句,Linux 中按下 Ctrl-Z,表示将该进程中断,在后台挂起,用 fg 命令可以重新切回到前台;按下 Ctrl-C 表示终止该进程。)

那么,如果真的想输入 Ctrl-D 怎么办?这时必须先按下 Ctrl-V,然后就可以输入 Ctrl-D,系统就不会认为这是 EOF 信号。Ctrl-V 表示按"字面含义"解读下一个输入,要是想按"字面含义"输入 Ctrl-V,连续输入两次就行了。

(完)


1.从缓冲区读走一个字符,相当于清除缓冲区

2.前面的 scanf()在读取输入时会在缓冲区中留下一个字符'\n'(输入完 s[i]的值后按回车键所致),所以如果不在此加一个 getchar()把这个回车符取走的话,gets()就不会等待从键盘键入字符,而是会直接取走这个“无用的”回车符,从而导致读取有误

3.getchar()是在输入缓冲区顺序读入一个字符(包括空格、回车和 Tab)getchar()使用不方便,解决方法:
(
1)使用下面的语句清除回车:
while(getchar()!='\n');
(2)用 getche()getch()代替 getchar(),其作用是从键盘读入一个字符(不用按回车),

注意要包含头文件<conio.h>

4.getchar()stdio.h 中的库函数,它的作用是从 stdin 流中读入一个字符,也就是说,如果 stdin 有数据的话不用输入它就可以直接读取了,第一次 getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的 getchar()再执行时就会直接从缓冲区中读取了。

实际上是 输入设备->内存缓冲区->程序 getchar

你按的键是放进缓冲区了,然后供程序 getchar

你有没有试过按住很多键然后等一会儿会滴滴滴滴响,就是缓冲区满了,你后头按的键没有存进缓冲区.

键盘输入的字符都存到缓冲区内,一旦键入回车,getchar 就进入缓冲区读取字符,一次只返回第一个字符作为 getchar 函数的值,如果有循环或足够多的 getchar 语句,就会依次读出缓冲区内的所有字符直到'\n'.要理解这一点,之所以你输入的一系列字符被依次读出来,是因为循环的作用使得反复利用 getchar 在缓冲区里读取字符,而不是 getchar 可以读取多个字符,事实上 getchar 每次只能读取一个字符.如果需要取消'\n'的影响,可以用 getchar();来清除,这里getchar();只是取得了'\n'但是并没有赋给任何字符变量,所以不会有影响,相当于清除了这个字符.还要注意的是这里你在键盘上输入 ssss 看到的回显正是来自于 getchar 的作用,如果用getch 就看不到你输入了什么.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值