scanf 忽略,无限循环

发布于 2024-10-21 19:05:03 字数 364 浏览 2 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

骄兵必败 2024-10-28 19:05:03

当您输入非数字的内容时,scanf 将失败并将这些字符保留在输入中。因此,如果您输入 hello,scanf 将看到 h,将其拒绝为对十进制数无效,并将其保留在输入中。下一次循环时,scanf 将再次看到 h,因此它会永远循环下去。

此问题的一种解决方案是使用 fgets 读取整行输入,然后使用 sscanf 解析该行。这样,如果 sscanf 失败,输入中不会留下任何内容。用户必须输入新行才能让 fgets 读取。

沿着这些思路:

char buffer[STRING_SIZE];
...
while(...) {
    ...
    fgets(buffer, STRING_SIZE, stdin);
    if ( sscanf(buffer, "%d", &price) == 1 )
        break;   // sscanf succeeded, end the loop
    ...
}

如果您只是按照另一个答案中的建议执行 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 enter hello, scanf will see the h, reject it as not valid for a decimal number, and leave it on the input. The next time through the loop, scanf will see the h 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 with sscanf. That way, if the sscanf fails, nothing is left on the input. The user will have to enter a new line for fgets to read.

Something along these lines:

char buffer[STRING_SIZE];
...
while(...) {
    ...
    fgets(buffer, STRING_SIZE, stdin);
    if ( sscanf(buffer, "%d", &price) == 1 )
        break;   // sscanf succeeded, end the loop
    ...
}

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, so sscanf returns 1 when it's successful.

烟─花易冷 2024-10-28 19:05:03

%d 格式适用于小数。当 scanf 失败时(输入了小数点以外的字符),导致失败的字符将保留为输入。

例子。

    int va;
    scanf("%d",&va);
    printf("Val %d 1 \n", val);

    scanf("%d",&va);
    printf("Val %d 2 \n", val);
    return 0;

所以不会发生转换。

如果之前发生输入失败,则 scanf 函数返回宏 EOF 的值
任何转换。否则,scanf函数返回输入项的数量
分配的数量可能少于规定的数量,如果提前分配,甚至为零
匹配失败

7.19.6。 scanf 函数 - JTC1/SC22/WG14 - C

因此,您应该注意 scanf 返回其自己的成功通知形式,

int scanf(char *format)

因此您也可以执行以下

do {
        printf("Enter Product \n");
}
while (scanf("%d", &sale.m_price) == 1);

if(scanf("%d", &sale.m_price) == 0)
        PrintWrongInput();

操作尽量远离 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.

    int va;
    scanf("%d",&va);
    printf("Val %d 1 \n", val);

    scanf("%d",&va);
    printf("Val %d 2 \n", val);
    return 0;

So no conversion occurs.

The scanf function returns the value of the macro EOF if an input failure occurs before
any conversion. Otherwise, the scanf function returns the number of input items
assigned, which can be fewer than provided for, or even zero, in the event of an early
matching failure

7.19.6. The scanf function - JTC1/SC22/WG14 - C

So you should note that scanf returns its own form of notice for success

int scanf(char *format)

so you could have also did the following

do {
        printf("Enter Product \n");
}
while (scanf("%d", &sale.m_price) == 1);

if(scanf("%d", &sale.m_price) == 0)
        PrintWrongInput();

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

单身情人 2024-10-28 19:05:03

在第一个数字之后,输入缓冲区中将出现一个“\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.

世界等同你 2024-10-28 19:05:03

因为缓冲区中有一个“\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 and scanf encounters a non-number (not just whitespace) or EOF because x 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.

凉栀 2024-10-28 19:05:03

它会进入无限循环,因为如果匹配失败, 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);

初见终念 2024-10-28 19:05:03

编辑:当我第一次写这个答案时,我对 scanf() 的工作原理非常愚蠢和无知。

  • 首先让我澄清一下,scanf() 不是一个损坏的函数,如果我不知道 scanf() 是如何工作的并且我不知道如何使用它,那么我可能还没有阅读 scans() 的手册,这不可能是 scanf() 的错。
  • 其次,为了了解代码有什么问题,您需要了解 scanf() 的工作原理。

当您在代码中使用 scanf("%d", &price) 时,scanf() 会尝试从以下位置读取一个整数:输入,但如果您输入非数值,scanf() 知道它不是正确的数据类型,因此它将在下一个循环周期将读取的输入放回到缓冲区中,但是无效的输入仍然在缓冲区中,这将导致 scanf() 再次失败,因为缓冲区尚未清空,并且这个循环永远持续下去。

为了解决这个问题,您可以使用 scanf() 的返回值,该值将是成功读取输入的数量,但是您需要通过刷新缓冲区来丢弃无效输入,以避免无限循环,按下 Enter 键时会刷新输入缓冲区,您可以使用 getchar() 函数暂停以获取输入来执行此操作,这会要求您按 enter 键,从而放弃无效的输入,请注意,无论您输入的数据类型是否正确,这都不会要求您按 enter 键两次,因为换行符仍将位于缓冲区中。在 scanf() 成功完成从输入中读取 integer 后,它会将 \n 放回缓冲区,因此 getchar( ) 会读取它,但由于您不需要它,因此可以安全地丢弃它:

#include <stdio.h>

int main(void)
{
    int flag = 0;
    int price = 0;
    int status = 0;
    while (flag == 0 && status != 1)
    {
        printf("\nEnter Product price: ");
        status = scanf("%d", &price);
        getchar();
        if (price == 0) 
            printf("input not valid\n"); 
        else 
            flag = 1;
    }   

    return 0;
}

Edit: Back when I first wrote this answer, I was so stupid and ignorant about how scanf() worked.

  • First of all let me clear something, scanf() is not a broken function, if I don't know how scanf() works and I don't know how to use it, then I probably haven't read the manual for scans() and that cannot be scanf()'s fault.
  • Second in order to understand what is wrong with your code you need to know how scanf() works.

When you use scanf("%d", &price) in your code, the scanf() tries to read in an integer 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 cause scanf() 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 the enter key is pressed, you can do this using the getchar() function to make a pause to get an input, which will require you to press the enter key thus discarding the invalid input, note that, this will not make you press the enter key twice whether or not you entered the correct data type, because the newline character will still be in the buffer. After scanf() has successfully finished reading the integer from input, it will put \n back into the buffer, so getchar() will read it, but since you don't need it, it's safe to discard it:

#include <stdio.h>

int main(void)
{
    int flag = 0;
    int price = 0;
    int status = 0;
    while (flag == 0 && status != 1)
    {
        printf("\nEnter Product price: ");
        status = scanf("%d", &price);
        getchar();
        if (price == 0) 
            printf("input not valid\n"); 
        else 
            flag = 1;
    }   

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文