这是今天做《C程序设计语言》习题1-8时发现的问题,本来以为是很简单的题目,结果还发现了很多不会的内容。
练习 1-8 编写一个统计空格、制表符与换行符个数的程序。
来看这样一个答案。
#include <stdio.h>
main()
{
int c, nl,nt,nw;
nl = 0;
nt = 0;
nw = 0;
while ((c = getchar()) != EOF){
if (c == '\n')
++nl;
if(c == '\t')
++nt;
if(c == 32)
++nw;
printf("this is %d\n", c);
}
printf("换行:%d\n", nl);
printf("制表符:%d\n", nt);
printf("空格:%d\n", nw);
}
程序的内容是while循环里统计输入的字符,CtrlD(Linux上的EOF)退出循环。
输入:Tab+Tab+CtrlD
认为的输出:直接退出while循环
实际的输出:没有退出while循环
实际上第二次输入CtrlD才退出了while循环,这和之前的预想不同,输入的CtrlD没有让循环退出,为什么?
经过一番搜寻找到了答案,记录一下。
首先解释一下getchar的工作原理,getchar会将用户的输入放在键盘缓冲区内,直到检测到回车认为输入完成,然后将这些字符统一处理。这个处理过程除了处理可读数据之外还会检测用户输入的CtrlD,CtrlC之类的EOF,根据处理EOF的方式可以分为阻塞式和非阻塞式两种。
阻塞式:在用户键入回车后才在缓冲区检测EOF,Windows一般是这种模式。
非阻塞式:在用户键入CtrlD之后立即响应的模式,Linux一般是这种模式。在这种模式下,如果CtrlD之前还有可读数据,那么CtrlD会被当成回车(因为之前还有数据,不能认为是无数据可读了,EOF代表的是没有数据可读的情况)
因此,在这个程序中输入的Tab+Tab+CtrlD中的CtrlD被当成是回车,因此没有退出while循环,第二个CtrlD被当做EOF而退出了循环。