键盘模拟文件尾EOF

getchar()指令

在stdio.h头文件中进行了定义,单次读取一个字符,包括空格、换行符等都能读取。很多时候,在不确定输入长度的情况下,常常使用while循环配合getchar()对字符串进行读取。判断while循环结束的条件需要认真考虑,下面主要分析文件尾条件下getchar()指令对文件尾条件EOF的读取情况。

EOF

EOF是一个宏定义,通常定义在stdio.h文件中(#define EOF -1)。主要用来判断文件的结束。有些操作系统使用内嵌的Ctrl+Z字符来标记,不过现在也有其他选择比如直接记录文件的大小信息来判断是否到结尾。
不论何种方式,在C语言中,用getchar()读取文件检测到文件结尾时便会返回一个特殊值EOF,scanf()函数也一样。

键盘输入模拟文件尾条件的测试

但在日常编程中,有时需要键盘输入模拟文件尾,以Windows为例,不少资料会说键入Crtl+Z可以模拟文件尾EOF。但实际上在运行测试过程中,会发现似乎并不是这么简单。
以一个C++简单程序为例:

//EOF test
#include <iostream>
using namespace std;
int main()
{
	int testArr[100];  //EOF为-1,char一般实现为无符号,故用int数组存储
	int i = 0;
	int count = 0;  //计数器
	while ((testArr[i++] = getchar()) != EOF) {
		cout << testArr[i - 1] << " ";
		count++;
	}
	cout <<"arr[i-1]:"<< testArr[i-1] << endl;
	cout << "Total counts:"<<count;
	return 0;
}

运行截图如下:(输入为abc+Ctrl+Z)
(输入为abc+Ctrl+Z)
输入:
a+b+c+Ctrl+Z
输出:
97 98 99 26
预期应该输出 a b c对应的ASCII码,然后输出arr[i-1]:-1;总共循环三次,输出Total counts:3,然后程序结束。
但实际上键入Cttl+Z后,确实立即进行了输出,但并没有如预料的终止循环,程序仍然在等待接下来的输入,同时值得注意的是,已经输出了4个值,前三个分别是a b c对应的ASCII码,这点没有问题,但第四个值26是如何得出的?

暂且先把这个问题留到后面解释,进一步执行,再次输入Ctrl+Z,回车:
完整运行结果

此时发现,程序真正地执行结束,而且数组有效读取的最后一个元素确实是-1。

原因分析

从第一次键入Ctrl+Z的结果开始分析,输出了4个值,显然,Ctrl+Z确实被读入了,但对应的并不是-1,而是ASCII码26,网上查到ASCII码表中26对应的是:
在这里插入图片描述
进一步查找发现,网上有这样一段描述:
“在微软的DOS和Windows(以及CP/M和许多DEC操作系统)中,读取数据时终端不会产生EOF。此时,应用程序知道数据源是一个终端(或者其它“字符设备”),并将一个已知的保留的字符或序列解释为文件结束的指明;最普遍地说,它是ASCII码中的替换字符(Control-Z,代码26)。一些MS-DOS程序,包括部分微软MS-DOS的shell(COMMAND.COM)和操作系统功能程序(如EDLIN),将文本文档中的Control-Z视为有意义数据的结尾,并且/或者在写入文本文档时将Control-Z添加到文档末尾”1

那么,现在可以明白了,26的来源确实是因为Ctrl+Z模拟的EOF,但此次读取并不会真正地将它理解成-1,而是理解成替换符(对应ASCII码26),同时刷新输入缓存。

相应的,当换行将缓冲区刷新后,第一个遇到就是Ctrl+Z,此时才会真正被理解成EOF(-1),终止循环。验证如下:当连续输入两个Ctrl+Z时也不会终止循环,而且计数仍然何之前一样,而当输入缓存区遇到的第一个是Ctrl+Z时会理解成遇到文件尾,立即结束输入。
在这里插入图片描述
在这里插入图片描述
在C Primer Plus第六版第8章中有这样一段描述:
“模拟EOF的概念是在使用文本界面的命令行环境中产生的。在这种环境中,用户通过击键与程序交互,由操作系统生成EOF信号。但是在一些实际应用中,却不能很好地转换成图形界面(如Windows和Macintosh),这些用户界面包含更复杂的鼠标移动和按钮点击。程序要模拟EOF的行为依赖于编
译器和项目类型。例如,Ctrl+Z可以结束输入或整个程序,这取决于特定的设置。”

C++ Primer Plus第五版第155页中提到:
“用于PC的Microsoft Visual C++、Borland C++5.5和GNU C++都能够识别行首的Ctrl+Z,但用户必须随后按下回车键。总之,很多PC环境都将Ctrl+Z视为模拟的EOF,但具体细节(必须在行首还是可以在任意位置,是否必须按下回车键等)各不相同”

由此可见,本人Windows10系统的计算机上,在命令窗口的文件尾条件应该是在行首输入Ctrl+Z,但之后不一定立即要按下回车

最后,在Linux系统上进行测试,发现也是需要在行首才能模拟EOF,输入Ctrl+D。输入为: a+b+c+Ctrl+D+Enter+Ctrl+D
输出如下图所示:

在这里插入图片描述
不过与Windows不同的地方在于,模拟EOF不在行首的情况下,Linux系统上单纯用Ctrl+D刷新输入缓存,立即向屏幕输出,但不会理解同时成替换字符(ASCII码26)而读取。


  1. https://baike.baidu.com/item/EOF/1017800?fr=aladdin ↩︎

发布了11 篇原创文章 · 获赞 1 · 访问量 84

猜你喜欢

转载自blog.csdn.net/weixin_44452361/article/details/104580031