scanf 忽略,无限循环
int flag = 0;
int price = 0;
while (flag==0)
{
printf("\nEnter Product price: ");
scanf("%d",&price);
if (price==0)
printf("input not valid\n");
else
flag=1;
}
当我输入有效数字时,循环将按预期结束。但是,如果我输入的不是数字,例如 hello
,那么代码就会进入无限循环。它只是不断打印输入产品价格:
和输入无效
。但它不会等我输入新号码。这是为什么?
int flag = 0;
int price = 0;
while (flag==0)
{
printf("\nEnter Product price: ");
scanf("%d",&price);
if (price==0)
printf("input not valid\n");
else
flag=1;
}
When I enter a valid number, the loop ends as expected. But if I enter something that isn't a number, like hello
, then the code goes into an infinite loop. It just keeps printing Enter Product price:
and input not valid
. But it doesn't wait for me to enter a new number. Why is that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
当您输入非数字的内容时,
scanf
将失败并将这些字符保留在输入中。因此,如果您输入hello
,scanf 将看到h
,将其拒绝为对十进制数无效,并将其保留在输入中。下一次循环时,scanf
将再次看到h
,因此它会永远循环下去。此问题的一种解决方案是使用
fgets
读取整行输入,然后使用sscanf
解析该行。这样,如果 sscanf 失败,输入中不会留下任何内容。用户必须输入新行才能让fgets
读取。沿着这些思路:
如果您只是按照另一个答案中的建议执行
getchar
,那么您可能会错过\n
字符,以防用户在数字后输入某些内容(例如一个空格,后面可能跟有其他字符)。您应该始终测试
sscanf
的返回值。它返回分配的转换次数,因此如果返回值与请求的转换次数不同,则意味着解析失败。在此示例中,请求了 1 次转换,因此成功时sscanf
返回 1。When you enter something that isn't a number,
scanf
will fail and will leave those characters on the input. So if you enterhello
, scanf will see theh
, reject it as not valid for a decimal number, and leave it on the input. The next time through the loop,scanf
will see theh
again, so it just keeps looping forever.One solution to this problem is to read an entire line of input with
fgets
and then parse the line withsscanf
. That way, if thesscanf
fails, nothing is left on the input. The user will have to enter a new line forfgets
to read.Something along these lines:
If you just do a
getchar
as suggested in another answer, then you might miss the\n
character in case the user types something after the number (e.g. a whitespace, possibly followed by other characters).You should always test the return value of
sscanf
. It returns the number of conversions assigned, so if the return value isn't the same as the number of conversions requested, it means that the parsing has failed. In this example, there is 1 conversion requested, sosscanf
returns 1 when it's successful.%d 格式适用于小数。当 scanf 失败时(输入了小数点以外的字符),导致失败的字符将保留为输入。
例子。
所以不会发生转换。
7.19.6。 scanf 函数 - JTC1/SC22/WG14 - C
因此,您应该注意
scanf
返回其自己的成功通知形式,因此您也可以执行以下
操作尽量远离 scanf。 scanf 或 扫描格式 不应用于交互式用户输入。 请参阅 C 常见问题解答 12.20
The %d format is for decimals. When scanf fails (something other a decimal is entered) the character that caused it to fail will remain as the input.
Example.
So no conversion occurs.
7.19.6. The scanf function - JTC1/SC22/WG14 - C
So you should note that
scanf
returns its own form of notice for successso you could have also did the following
Also keep in the back of your head to try to stay away from scanf. scanf or scan formatted should not be used for interactive user input. See the C FAQ 12.20
在第一个数字之后,输入缓冲区中将出现一个“\n”(您输入数字时按下的回车键),因此在第二次迭代中,scanf调用将失败(因为\n不是数字),scanf将不从缓冲区中删除 \n,因此在下一次迭代中它将再次失败,依此类推。
您可以通过在 scanf 之后调用 getchar() 读取 '\n' 来解决此问题。
After the first number, a '\n' will be in the input buffer (the return you pressed to input the number), so in the second iteration the scanf call will fail (becouse \n isn't a number), scanf will not remove that \n from the buffer, so in the next iteration it will fail again and so on.
You can fix that by reading the '\n' with a getchar() call after scanf.
因为缓冲区中有一个“\n”而说会的“答案”是错误的——
scanf("%d", ...)
跳过空格,包括换行符。如果
x
包含 0 并且scanf
遇到非数字(不仅仅是空格)或 EOF,则会进入无限循环,因为x
将保持 0而且它不可能变成别的样子。只需查看您的代码并思考它在这种情况下会做什么就应该清楚这一点。The "answers" that say it will because there is a '\n' in the buffer are mistaken --
scanf("%d", ...)
skips white space, including newlines.It goes into an infinite loop if
x
contains 0 andscanf
encounters a non-number (not just whitespace) or EOF becausex
will stay 0 and there's no way for it to become otherwise. This should be clear from just looking at your code and thinking about what it will do in that case.它会进入无限循环,因为如果匹配失败, scanf() 将不会消耗输入令牌。 scanf() 将尝试一次又一次匹配相同的输入。你需要刷新标准输入。
if (!scanf("%d", &sale.m_price))
fflush(标准输入);
It goes into an infinite loop because scanf() will not consumed the input token if match fails. scanf() will try to match the same input again and again. you need to flush the stdin.
if (!scanf("%d", &sale.m_price))
fflush(stdin);
编辑:当我第一次写这个答案时,我对 scanf() 的工作原理非常愚蠢和无知。
scanf()
不是一个损坏的函数,如果我不知道scanf()
是如何工作的并且我不知道如何使用它,那么我可能还没有阅读scans()
的手册,这不可能是scanf()
的错。scanf()
的工作原理。当您在代码中使用
scanf("%d", &price)
时,scanf()
会尝试从以下位置读取一个整数
:输入,但如果您输入非数值,scanf()
知道它不是正确的数据类型,因此它将在下一个循环周期将读取的输入放回到缓冲区中,但是无效的输入仍然在缓冲区中,这将导致scanf()
再次失败,因为缓冲区尚未清空,并且这个循环永远持续下去。为了解决这个问题,您可以使用 scanf() 的返回值,该值将是成功读取输入的数量,但是您需要通过刷新缓冲区来丢弃无效输入,以避免无限循环,按下 Enter 键时会刷新输入缓冲区,您可以使用 getchar() 函数暂停以获取输入来执行此操作,这会要求您按
enter
键,从而放弃无效的输入,请注意,无论您输入的数据类型是否正确,这都不会要求您按enter
键两次,因为换行符
仍将位于缓冲区中。在scanf()
成功完成从输入中读取integer
后,它会将\n
放回缓冲区,因此getchar( )
会读取它,但由于您不需要它,因此可以安全地丢弃它:Edit: Back when I first wrote this answer, I was so stupid and ignorant about how
scanf()
worked.scanf()
is not a broken function, if I don't know howscanf()
works and I don't know how to use it, then I probably haven't read the manual forscans()
and that cannot bescanf()
's fault.scanf()
works.When you use
scanf("%d", &price)
in your code, thescanf()
tries to read in aninteger
from the input, but if you enter a non numeric value,scanf()
knows it isn't the right data type, so it puts the read input back into the buffer, on the next loop cycle however the invalid input is still in the buffer which will causescanf()
to fail again because the buffer hasn't been emptied, and this cycle goes on forever.In order to tackle this problem you can use the return value of
scanf()
, which will be the number of successful inputs read, however you need to discard the invalid inputs by flushing the buffer in order to avoid an infinite loop, the input buffer is flushed when theenter
key is pressed, you can do this using thegetchar()
function to make a pause to get an input, which will require you to press theenter
key thus discarding the invalid input, note that, this will not make you press theenter
key twice whether or not you entered the correct data type, because thenewline character
will still be in the buffer. Afterscanf()
has successfully finished reading theinteger
from input, it will put\n
back into the buffer, sogetchar()
will read it, but since you don't need it, it's safe to discard it: