如何清除 C 程序中的标准输入?

How can I clear stdin in a C progam?

这是一个看似简单的问题,但我已经太久没能回答了:

我正在尝试使用 fgets() 在 C 程序中读取用户的输入。但是,我 运行 遇到的问题是,如果用户输入的字符多于 fgets() 设置为读取的字符数,下一次从用户读取字符串的调用会自动读取标准输入缓冲区中的剩余字符,而这这不是我想要的行为。

我尝试了很多方法来清除标准输入流,虽然我知道类似

while(getchar()!='\n'); 会起作用,这需要用户再输入一次,这不是我想要的。

代码的结构如下所示:

    void read_string(char *s, int width){
        fgets(s,width,stdin);
        clear_stdin();
        .
        .   
    }

    while (1){
        read_string()
        .
        .
    }

但是我无法得到一个正常工作的 clear_stdin() 函数。我究竟该如何清除标准输入,而无需用户不必要地按两次回车键?

不能以可移植的方式清除stdin(因为<stdio.h> is specified doing that). BTW, stdin can usually be not only a terminal, but also a redirection or a pipe (or even perhaps some socket没有函数)。细节当然重要(例如您的操作系统 and/or 运行 环境)。

您可以避免使用 stdio 并在 POSIX 系统上使用 operating system specific ways to deal with standard input (e.g. working at the file descriptor 级别。

在 Linux(具体而言),您可能会阅读更多关于 the Tty demystified, and code low level code based on such knowledge. See termios(3). Consider using readline(3) 的内容。

您可以use (on Linux at least) getline(3)读取堆分配的行缓冲区。

while ((getchar()) != '\n');

这并不总是有效...(但从好的方面来说,它不适用的情况与它适用的情况一样便携) .但是如果stdin没有被重定向,用户输入的terminal char,除非手动EOF,否则通常会是一个换行符.在您提取您期望的内容后,假设您不期望 \n,您可以排空直到(并包括)'\n' 之前的内容,然后重新迭代。正如其他人所建议的那样,在大多数情况下,有更高级别的接口可以比手动边缘案例处理更可靠地处理这些细节。

More Details on Challenge and Solutions 此 link 在其标题中包含 "C\C++" 的主要错误,它不作为实体存在。请放心,单独 给出了 C 示例,与备用 C++ 示例不同。

为了实现您想要的效果 — 如果您提供的缓冲区已满,则读取并忽略换行符之前的额外字符 — 您需要有条件地读取换行符,只有在没有换行符时才这样做已经在读取的输入缓冲区中。

void read_string(char *s, int width)
{
    if (fgets(s, width, stdin) != 0)
    {
        size_t length = strlen(s);
        if (length > 0 && s[length-1] != '\n')
        {
            int c;
            while ((c = getchar()) != '\n' && c != EOF)
                ;
        }
        /* Use the input data */
    }
    else
        /* Handle EOF or error */
}

该技术的另一部分是确保您使用足够大的缓冲区,这样任何人都不太可能溢出它。考虑 char buffer[4096]; 作为开标;如果您愿意,可以增加它。这使得任何人都不太可能(能够)在一行中键入足够的数据来溢出您提供的缓冲区,从而避免了这个问题。

另一种选择是使用 POSIX getline()。它将一行读入已分配的 space,分配更多 space 直到数据适合(或者您 运行 内存不足)。与 fgets() 相比,它至少还有一个主要优势——它报告它读取的行中的字符数,这意味着它不会被空字节混淆('[=14=]',通常输入为 Control-@) 输入。相比之下,您无法判断在第一个空字节之后是否输入了任何数据 fgets();您必须假设输入在第一个空字节处停止。

请注意,问题 (while (getchar() != '\n');) 中显示的简单循环如果在读取换行符之前遇到 EOF 就会变成无限循环。