谈一谈getchar()、EOF和Ctrl+D

时间:2021-12-15 18:43:37

getchar()

  getchar从stdio流中读字符,getchar有一个int型的返回值.当程序调用getchar时.程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符.getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕.如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取.也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键。[以上定义来自百度百科]

EOF

  计算机术语,缩写通常为EOF(End Of File),在操作系统中表示资料源无更多的资料可读取。资料源通常称为档案或串流。
  在C语言中,或更精确地说成C标准函数库中表示文件结束符(end of file)。在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~255,不可能出现-1,因此可以用EOF作为文件结束标志。
  在 UNIX中, EOF表示能从交互式 shell (终端) 送出 Ctrl+D (习惯性标准)。在微软的 DOS 与 Windows 中能送出 Ctrl+Z。在控制台要输入eof的话 按ALT+65535就可以了。[以上概念来自百度百科]
  所以,EOF并不属于文件内容的一部分,它只是读不到更多内容时返回的结束标志。

看一个例子

1、

#include<stdio.h>
int main()
{
int a;
while((a=getchar())!=EOF)
{
printf("a=%d\n",a);
}
printf("end:%d\n",a);
return 0;
}

下面是几种不同情况下的输出:
(1)直接按Ctrl+D后,getchar()返回-1,退出
谈一谈getchar()、EOF和Ctrl+D
(2)输入一串字符后,再按Ctrl+D
谈一谈getchar()、EOF和Ctrl+D
所有字符被从缓冲区读出,与按回车不同的是,回车也会被送入缓冲,但Ctrl+D没有在缓冲区中体现出来。本来想,如同(1)一样,Ctrl+D相当于EOF(-1),在输出所有字符后,getchar()会遇到EOF输出-1的。
(3)输入一串字符后,连续按两次Ctrl+D
谈一谈getchar()、EOF和Ctrl+D
最后会得到-1,退出循环。
既然getchar()是从缓冲区中读字符,而根据(2)Ctrl+D是没有放入缓冲区的,为什么按两次Ctrl+D就会输出-1呢?
在网上查到的解释如下:
  输入缓冲是行缓冲。当从键盘上输入一串字符并按回车后,这些字符会首先被送到输入缓冲区中存储。每当按下回车键后,就会检测输入缓冲区中是否有了可读的数据。还会对键盘上是否有作为流结束标志的 Ctrl+Z(windows) 或者 Ctrl+D 键 按下作出检查,其检查的方式有两种:阻塞式以及非阻塞式。

  阻塞式检查方式指的是只有在回车键按下之后才对此前是否有 Ctrl+Z 组合键按下进行检查,非阻塞式样指的是按下 Ctrl+ D 之后立即响应的方式。如果在按 Ctrl+D 之前已经从键盘输入了字符,则 Ctrl+D的作用就相当于回车(但是回车自己也会进入缓冲),即把这些字符送到输 入缓冲区供读取使用,此时Ctrl+D不再起流结束符的作用。如果按 Ctrl+D 之前没有任何键盘输入,则 Ctrl+D 就是流结束的信号。

  Windows系统中一般采用阻塞式检查 Ctrl+Z、Unix/Linux系统下一般采用非阻塞式的检查 Ctrl+D。楼主是在Windows系统下,因此使用阻塞式的 Ctrl+Z 来标识流的结束。这种阻塞式的方式有一个特点:只有按下回车之后才有可能检测在此之前是否有Ctrl+Z按下。还有一个特点就是:如果输入缓冲区中有可读的数据则不会 检测Ctrl+Z(因为有要读的数据,还不能认为到了流的末尾)。还有一点需要知道:Ctrl+Z产生的不是一个普通的ASCII码值,也就是说它产生的 不是一个字符,所以不会跟其它从键盘上输入的字符一样能够存放在输入缓冲区。

[摘自:http://wenku.baidu.com/view/44e58e1d227916888486d744.html]
2、

#include<stdio.h>
int main()
{
int a;
while((a=getchar())!=EOF)
{
sleep(1);
printf("%d\n",a);
}
printf("end:%d\n",a);
return 0;
}

在缓冲区字符没读完的时候按Ctrl+D
谈一谈getchar()、EOF和Ctrl+D
结果在输出所有字符后,getchar()返回了-1,说明只要没有键盘输入,直接Ctrl+D就会起作用。
  我觉得可以这样理解,每按一次Ctrl+D就表示结束一轮输入,此时Ctrl+D就告诉getchar()你去读缓冲区吧。当Ctrl+D之前有字符输入时,getchar就会正常读到字符。当直接按Ctrl+D时,缓冲区没有任何字符送进去,getchar()去读的时候什么也没读到,就会出错返回-1。

3、

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
int c;
system("stty raw");
/* 现在的终端驱动处于一次一个字符模式 */
while(1)
{
c = getchar();
putchar(c);
}

/* 终端驱动处又回到一次一行模式 */
system("stty cooked");

return 0;
}

stty raw 可以实现键入一个字符立即读出的效果。此时回车不再起换行作用,按回车后光标会定位到行开头。