当初学c语言的时候,都知道EOF是文件结束符,end of file的意思,一般通过EOF来标识输入或文件的结束(终端输入的话windows系统中是Ctrl+Z键,linux系统是Ctrl+D键),如上面那段代码所示,以前一直以为是不断读入终端输入的字符,一直到读到^Z为止,但现在发现却不是这么简单。

一个小例子

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char ch;
    while((ch=getchar())!=EOF){
        printf("%d %c\n",ch,ch);
    }
    system("pause");
    return 0;
}

简单运行一下这个小程序,如果输入 abcd^Z,,然后回车,程序运行结果如下:
这里写图片描述

可以看到程序此时并没有结束,需要再键入Ctrl+Z,回车,才会结束:
这里写图片描述

这是为什么呢?这得先讲讲EOF和getchar()。

EOF

EOF如字面意思,就是文件结尾(End Of File),是操作系统无法从数据源读取更多数据的情形。数据源通常为文件或流。
EOF的真实值与不同的平台有关(但通常是-1,比如在glibc中),并且不等于任何有效的字符代码。

一般在c/c++中EOF是个宏定义,其值为-1,也就是说,EOF并不是个字符,没有什么特殊的结构,只是一个值为-1的宏定义而已。

getchar()

定义:int getchar(void);
作用:从 stdin 读取下一个字符,等价于 getc(stdin) 。
返回值:成功时为获得的字符,失败时为 EOF 。

上面说到EOF其实只是-1,并不是一个字符,这里的getchar()函数返回的其实也不是字符,而是一个int整形。当getchar()读取字符成功时,其返回的就是字符的ASCII值,失败时返回EOF,即-1。所以能终止上面while循环的条件是getchar()读取失败返回-1,那怎么样读取失败呢?这里需要先讲讲^Z这个字符。

Ctrl+Z和Ctrl+D

大一刚开始学c的时候,只知道windows通过Ctrl+Z来终止上面的while循环输入,linux通过Ctrl+D,当时以为键入Ctrl+Z,那个^Z字符就是EOF,getchar得到EOF自然就终止了,现在看来,EOF并不是一个字符,而getchar成功时也不可能返回EOF。其实如上面的运行结果所示,^Z字符的ASCII值是26,也就是说键入Ctrl+Z后,其实输入的是一个ASCII值为26的字符。

那如果Ctrl+Z输入是一个字符的话,getchar()怎么会返回EOF呢?因为输入缓冲是行缓冲,在windows系统下按下回车后才会送到输入缓冲区中存储。每当按下回车键后,就会检测输入缓冲区中是否有了可读的数据以及Ctrl+Z这样的流结束的标志。如上面运行结果所示,当Ctrl+Z前面有其他字符时,此时系统认为缓冲区中有可读的数据,系统不会检测Ctrl+Z(因为有要读的数据,还不能认为到了流的末尾);而当Ctrl+Z前面没有其他字符时,系统此时会检测到Ctrl+Z,此时getchar()就会读取失败,返回EOF。所以如果需要终端输入Ctrl+Z终止输入,需要另起一行输入Ctrl+Z才行。

网上查的关于Ctrl+Z和Ctrl+D的解释:

输入缓冲是行缓冲。当从键盘上输入一串字符并按回车后,这些字符会首先被送到输入缓冲区中存储。每当按下回车键后,就会检测输入缓冲区中是否有了可读的数据。还会对键盘上是否有作为流结束标志的 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码值,也就是说它产生的 不是一个字符,所以不会跟其它从键盘上输入的字符一样能够存放在输入缓冲区。

Logo

更多推荐