#include <stdio.h>
int main()
{
int c;
while((c=getchar())!=EOF)
putchar(c);
return 0;
}
在我对C的有限暴露中,只要C!= EOF,while条件将被执行,其中将基本上打印c然后等待下一个char并尝试检查是否违反条件。因此,对于我们输入的每个char,putchar将执行。然而,当我运行可执行文件时,似乎发生的事情是print语句仅在我按下新行(Enter)时才有效,并且它有某种类型的缓冲区可以在输入中打印整行。我没有看到代码中的任何缓冲区将保持字符,直到按下新行,那么这里做了什么?这些字符存储在哪里直到按下新行?
当像这样从控制台读取时,你的程序实际上根本没有接收任何输入,直到你按下回车键,然后它立即读取并处理整行。
你的程序不知道这些字符甚至存在,直到你按Enter键,此时它们被发送到stdin缓冲区。从这里开始,你的循环将读取并打印每个字符(包括新行),直到缓冲区为空(意味着它将等待更多输入),或者到达文件末尾。
缓冲是在读取数据和写入数据时发生的。
stdin
和stdout
,独立可以是字符,线或完全缓冲。
在您的常见情况下,两者都是行缓冲的。
在输入(getchar()
)被击中之前,不会给'\n'
输入。 (你可以回空间输入吗?)并且在打印'\n'
之前不会显示输出。
getchar()
和putchar()
函数是stdio
包的一部分,它使缓冲输入/输出。
这意味着,尽管您实际请求的字符数量(仅在您的情况下为一个),缓冲机制使字符在缓冲区中等待,直到整个缓冲区(或一行,如果stdin
来自tty设备)是填充。
这里发生的是,在第一个getchar()
上,请求一个完整的缓冲区填充,并且只用您键入的输入行部分填充。之后,所有getchar()
调用从缓冲区中获取单个字符,直到它再次为空,并且那时,请求另一个完整的缓冲区。
这使得单个字符处理成为一种有效的处理方式。这也发生在输出上。 putchar()
函数只填充缓冲区,直到它完全填满(或者,如果您的输出通道是tty设备,直到您请求输出\n
字符),当它是,则将完整缓冲区输出到文件/设备。
此外,各种版本的unix中的终端驱动程序,在线模式下工作,这意味着直到你按下<ENTER>
键,你才得到任何发送到程序的东西。这将允许您通过使用擦除键(退格键)和/或终止(Cntrl-U)键来纠正键控时所犯的错误。这是在Windows控制台应用程序中模拟的,因此您可能需要输出设备进入原始模式才能以基于字符的方式输入。
如果你想让你的程序一次读取一个字符,你需要绕过stdio的缓冲区(通过setbuf(NULL)
函数调用,或使用read(2)
系统调用来读取一个字符,这可以通过以下方式完成:
char c;
int res = read(0, &c, 1);
if (res < 0) { /* error */
...
} else if (res == 0) { /* EOF in input */
...
} else { /* 1, as you requested only one char */
... /* one character was read. */
}
)并在实际阅读之前将终端驱动程序置于原始模式(通过tcsetattr()
和tcgetattr()
调用,请参阅termios(4)
手册页以获取有关如何执行此操作的详细信息)。在这种情况下,您必须在终止程序之前将终端状态返回到行模式,否则您将遇到麻烦。