每次输入后刷新stdin - 哪种方法不是错误的?

时间:2013-06-22 07:32:36

标签: c flush

Mark Lakata指出我的问题中没有正确定义垃圾之后我想出了这个。我会保持更新以避免混淆。


我正在尝试获取一个我可以在提示用户输入之前调用的函数,例如printf("Enter your choice:);跟随scanf,并确保只有在提示之后输入的内容才会被{ {1}}作为有效输入。

据我所知,所需的功能是完全刷新标准输入的功能。这就是我想要的。因此,对于此函数,scanf是用户输入中的所有内容,即在该用户提示之前的整个用户输入。


在C中使用"garbage"时,输入缓冲区中总会存在额外输入的问题。所以我在寻找一个我在每次scanf调用后调用的函数来解决这个问题。我使用thisthisthisthis来获得这些答案

scanf()

这三个人都是通过命中试验和参考文献找到的。但是在我的所有代码中使用其中任何一个之前,我想知道其中是否有任何错误?

编辑:

感谢Mark Lakata第3个错误。我在问题中纠正了它。

EDIT2:

Jerry Coffin回答后,我在代码中使用该程序测试了前两种方法:使用GNU GCC编译器阻止IDE 12.11(版本未在编译器设置中声明)。

//First approach
scanf("%*[^\n]\n");

//2ndapproach
scanf("%*[^\n]%*c");

//3rd approach
int c;
while((c = getchar()) != EOF) 
    if (c == '\n') 
        break;

我使用了以下2个输入

第一次测试输入(2个换行但在垃圾输入中间没有空格)

#include<stdio.h>

int main()
{
    int x = 3; //Some arbitrary value
    //1st one
    scanf("%*[^\n]\n");
    scanf("%d", &x);
    printf("%d\n", x);

    x = 3;
    //2nd one
    scanf("%*[^\n]%*c");
    scanf("%d", &x);
    printf("%d", x);
}

对于第一个,我通过abhabdjasxd 23 bbhvdahdbkajdnalkalkd 46 语句获得了以下输出

printf

即。两个代码都正常工作。

第二次测试输入 :( 2个垃圾输入中间带空格的换行符)

23
46

对于第二个,我通过hahasjbas asasadlk 23 manbdjas sadjadja a 46 语句获得了以下输出

printf

因此我发现第二个不会处理额外的垃圾输入空格。因此,它不是垃圾输入的万无一失。

我决定试用第3个测试用例(垃圾包括非空格字符前后的换行符)

23
3

答案是

``
hahasjbas asasadlk


23

manbdjas sadjadja a


46

即。在这个测试案例中都失败了。

5 个答案:

答案 0 :(得分:9)

前两个略有不同:它们都读取并忽略所有字符直到新行。然后第一个跳过所有连续的空格,所以在执行之后,你读的下一个字符将是非空格。

第二个读取并忽略字符,直到它遇到一个新行然后再读取(并丢弃)一个字符。

如果您有(例如)双倍行距文本,则会显示差异,例如:

line 1

line 2

让我们假设你读到第1行中间的某个地方。如果你执行第一个,你读入的下一个字符将是第2行的'l'。如果你执行第二个字符,那么下一个字符你读入将是第1行和第2行之间的换行符。

至于第三种情况,如果我要这样做,我会做类似的事情:

int ch;
while ((ch=getchar()) != EOF && ch != '\n')
    ;

...是的,这确实可以正常工作 - &&强制一个序列点,所以首先评估它的左操作数。然后有一个序列点。然后,当且仅当左操作数计算为true时,它才会计算其右操作数。

至于性能差异:既然你正在处理I / O,那么所有这些都将永远受I / O限制的问题几乎没有。尽管它有明显的复杂性,scanf(和公司)通常是经过多年使用并经过多年精心优化的代码。在这种情况下,手动循环可能会慢得多(例如,如果getchar的代码没有内联扩展),或者它可能大约相同的速度。如果编写标准库的人不称职,那么唯一可能显着提高速度的方法就是。

至于可维护性:IMO,任何声称知道C 的人都知道scanf的扫描集转换。这既不是新的也不是火箭科学。任何不了解它的人都不是一个称职的C程序员。

答案 1 :(得分:3)

前两个例子使用了我甚至不知道存在的scanf功能,我相信很多其他人都不知道。能够在将来支持某项功能非常重要。即使它是众所周知的功能,与第3个示例相比,读取格式字符串效率也会更低。

第三个例子看起来不错。

(编辑历史:我犯了一个错误,说ANSI-C并不保证&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp; and ;&amp;。我不确定K&amp; RC,但我找不到任何参考,也没有人使用它...)

答案 2 :(得分:1)

许多其他解决方案存在的问题是,当没有任何内容可以刷新时,它们会导致程序挂起并等待输入。等待EOF是错误的,因为在用户完全关闭输入之前你没有得到它!

在Linux上,以下将执行非阻塞刷新:

// flush any data from the internal buffers
fflush (stdin);

// read any data from the kernel buffers
char buffer[100];
while (-1 != recv (0, buffer, 100, MSG_DONTWAIT))
  {
  }

Linux手册页说明fflush上的stdin是非标准的,但“大多数其他实现与Linux的行为相同。”

MSG_DONTWAIT标志也是非标准的(如果没有数据要传递,它会导致recv立即返回。)

答案 3 :(得分:-1)

You should use getline/getchar:

#include <stdio.h>

int main()
{
  int bytes_read;
  int nbytes = 100;
  char *my_string;

  puts ("Please enter a line of text.");

  /* These 2 lines are the heart of the program. */
  my_string = (char *) malloc (nbytes + 1);
  bytes_read = getline (&my_string, &nbytes, stdin);

  if (bytes_read == -1)
    {
      puts ("ERROR!");
    }
  else
    {
      puts ("You typed:");
      puts (my_string);
    }

  return 0;

答案 4 :(得分:-1)

我认为如果您仔细查看此页面的右侧,您会看到许多类似于您的问题。你可以在windows上使用fflush()。