【问题标题】:Reading from stdin, and clearing stdin afterward从标准输入读取,然后清除标准输入
【发布时间】:2015-01-23 02:39:58
【问题描述】:

这是一个循环,从stdin 重复获取两个字符并输出它们。

char buf[2];
while (1)
{
    printf("give me two characters: ");
    fflush(stdout);

    read(0, buf, 2);
    printf("|%c%c|\n", buf[0], buf[1]);
}

问题在于,当在终端上按下 ENTER 键时,会插入一个换行符并保留在 stdin 缓冲区中,并将在下次调用 read 时被抓取。理想情况下,我希望每次调用 read 时都有一个清晰的 stdin 缓冲区,没有留下任何以前的垃圾。你能推荐一个好的解决方案吗?

我尝试了各种库调用,例如fgets,但是它们遇到了同样的问题。我正在考虑使用fpurge 手动清除缓冲区,但有人告诉我这不是一个好的解决方案。

这里的问题是剩余的输入应该被视为垃圾,并被丢弃。但是,当我下次调用 read 时,我无法区分剩余输入和新输入。

感谢您的意见。

【问题讨论】:

  • 如果您的输入来自文件或来自其他进程的管道怎么办?在这些非交互式情况下,“清除标准输入”没有多大意义......如果我是你,我会考虑将换行符视为我正在解析的输入的一部分,而不是试图将其从缓冲区中删除你要的。
  • 我看不出fgets 有同样的问题。哦,你一定是这样做了char buf[2]; fgets(buf,2,stdin); 是的,确实有同样的问题,但这不是如何使用fgets
  • 您想准确读取两个字符,并在键入第二个字符后立即返回读取?还是您想读取一行的前两个字符,然后删除该行的其余部分?或者是其他东西?您需要有明确的要求才能获得准确的解决方案。
  • @iharob 我明白你现在在说什么了。第二次调用 read 取出缓冲区中剩余的所有内容。
  • @Cocksure:如果你真的想读取两个字符(即,不等待用户按下回车键),你需要在 termios 设置中取消设置 ICANON 标志,并将VMIN 更改为 2。(或者您可以将其更改为 1 并一次读取一个字符,由于各种原因,这通常是一个更好的主意。)Michael Kerrisk 的“Linux 编程接口”中有示例代码,我推荐如果您想认真对待低级 Linux 编程(免责声明:作者是朋友)。代码在线:man7.org/tlpi/code/online/book/tty/test_tty_functions.c.html

标签: c stdin


【解决方案1】:

您可以添加 getchar();阅读更多'\n':

#include <stdlib.h>
#include <stdio.h>
char buf[2];

main() {
while (1)
{
    printf("give me two characters: ");
    fflush(stdout);

    read(0, buf, 2);
    getchar();
    printf("|%c%c|\n", buf[0], buf[1]);
}
}

give me two characters: ab
|ab|
give me two characters: xy
|xy|

【讨论】:

  • 如果有人在输入之后(和换行符之前)键入一个空格,它将中断。防止这种情况的一个好方法是在循环中使用getchar,直到你得到一个换行符。
  • @RafaelLerm 啊,是的,这是个好主意。感谢您的意见