在Mark Lakata
指出我的问题中没有正确定义垃圾之后我想出了这个。我会保持更新以避免混淆。
我正在尝试获取一个我可以在提示用户输入之前调用的函数,例如printf("Enter your choice:);
跟随scanf
,并确保只有在提示之后输入的内容才会被{ {1}}作为有效输入。
据我所知,所需的功能是完全刷新标准输入的功能。这就是我想要的。因此,对于此函数,scanf
是用户输入中的所有内容,即在该用户提示之前的整个用户输入。
在C中使用"garbage"
时,输入缓冲区中总会存在额外输入的问题。所以我在寻找一个我在每次scanf调用后调用的函数来解决这个问题。我使用this,this,this和this来获得这些答案
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
即。在这个测试案例中都失败了。
答案 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()。