如何在fgets循环中正确刷新stdin

Big*_*olf 6 c stdin

我已经找到了while((c = getchar()) != '\n' && c != EOF)在这里使用清除stdin 几次的例子,并尝试在通过fgets获取输入的循环中使用它.我需要刷新,因为循环从最后一个输入获取\n字符并再次运行它.

那么现在发生的是我现在必须按两次输入.为什么会发生这种情况,我该如何解决这个问题呢?

#define BUFFER_LIMIT 50
do
{
  int c;
  while ((c = getchar()) != '\n' && c != EOF);

  printf("console> ");
  fgets(input_buffer, BUFFER_LIMIT-1, stdin);

  if(do_something(input_buffer))
    break;
} while(strncmp(input_buffer, "quit", 4) != 0);
Run Code Online (Sandbox Code Playgroud)

srd*_*vic 8

那么现在发生的是我现在必须按两次输入.为什么会发生这种情况,我该如何解决这个问题呢?

好吧,这就是你的代码正在做的事情 - 它首先读取char-by-char,直到它找到换行符.然后它调用fgets()哪个......好吧,读取直到找到换行符(可能是char-by-char,但也可能以其他方式).

你可以尝试fflush(stdin),但不能保证做你想做的事情(它只保证输出缓冲区,而不是输入).

此外,您可以尝试setbuf(stdin, NULL)在标准输入上禁用缓冲,因此无需刷新.我在不同的系统上尝试了几次并且它有效,但是这个功能的文档并不是100%明确的.


Ste*_*mit 5

有不幸的是,许多有关C.“冲洗输入”混乱产生了困惑几乎全部来自对流行的,但是,有缺陷的奇怪事实的一个scanf功能:它一般也不能读取输入的实线,并且一般离开\n转换其输入后输入流上的换行符。例如,如果你编写一个程序,它说

printf("Type a number:\n");
scanf("%d", &n);
Run Code Online (Sandbox Code Playgroud)

如果用户输入“123”并按回车键,数字123将被存储到变量中n,但与回车键对应\n字符将留在输入流中。如果您的程序接下来要做的是调用fgets, 或getchar,想象您将开始读取用户键入的下一行输入,您的程序将立即读取剩余的换行符。看起来好像用户输入了一个额外的空行或其他东西。

这个问题非常普遍。大量的初学 C 程序员已经被它困住了。简而言之,有三种推荐的修复方法:

  1. 在调用这样的函数后scanf,在输入缓冲区中留下换行符,并且在调用类似getcharfgets希望从新行开始的函数之前,使用小循环while((c = getchar()) != '\n' && c != EOF)读取并丢弃scanf留在输入缓冲区中的换行符。

  2. 根本不要使用scanf,或者如果使用,不要尝试将其与对getchar或 的调用混合使用fgets

  3. (流行但问题严重)调用fflush(stdin)以刷新不需要的输入。

#3 的问题已经被广泛讨论,所以我不会再谈论那些问题或解决方案。推荐的“便携式”替代方案是 #1,但它显然只有在输入中至少有一个不需要的换行符等待刷新时才有效。如果没有,解决方案 #1 将错误地读取并丢弃一行所需的输入。

所以你不能到处使用#1。你不能在你的程序中随意洒它;你不能在任何你可能使用过的地方使用它fflush(stdin)。一般来说,正如已经提到的,只有在调用之后scanf和调用getcharor之前才需要它fgets

在问题的代码片段中,可能根本不需要使用解决方案#1。该fgets功能完全能够自己干净地读取各个输入行。不一定需要额外刷新输入或丢弃换行符。(但是,如果在scanf下面调用了down do_something(),则可能需要额外的换行处理。)