scanf忽略,无限循环

时间:2011-03-12 21:50:32

标签: c infinite-loop 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,那么代码会进入无限循环。它只是保持打印Enter Product price:input not valid。但它不等我输入一个新号码。那是为什么?

6 个答案:

答案 0 :(得分:4)

当您输入不是数字的内容时,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。

答案 1 :(得分:3)

%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. The scanf function - 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或扫描格式化不应用于交互式用户输入。 See the C FAQ 12.20

答案 2 :(得分:1)

在第一个数字之后,'\ n'将在输入缓冲区中(您按下的返回数字输入),因此在第二次迭代中scanf调用将失败(因为\ n不是数字) ,scanf不会从缓冲区中删除\ n,因此在下一次迭代中它将再次失败,依此类推。

你可以通过在scanf之后用getchar()调用来读取'\ n'来解决这个问题。

答案 3 :(得分:1)

因为缓冲区中有'\ n'而错误的“答案”是错误的 - scanf("%d", ...)会跳过空格,包括换行符。

如果x包含0且scanf遇到非数字(不仅仅是空格)或EOF,它将进入无限循环,因为x将保持为0并且无法使用它否则。通过查看代码并考虑在这种情况下它将做什么,这应该是清楚的。

答案 4 :(得分:0)

它进入无限循环,因为如果匹配失败,scanf()将不会使用输入令牌。 scanf()将尝试反复匹配相同的输入。你需要冲洗标准输入。

if(!scanf(“%d”,&amp; sale.m_price))    fflush(标准输入);

答案 5 :(得分:0)

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

  • 首先让我清楚一点,scanf()不是一个破碎的功能,如果我不知道scanf()是如何工作的,我不知道如何使用它,那么我可能是避风港请阅读scans()的手册,但这不是scanf()的错误。
  • 其次,为了了解您的代码有什么问题,您需要了解scanf()的工作原理。

当您在代码中使用scanf("%d", &price)时,scanf()会尝试从输入中读取integer,但如果输入非数字值,则scanf()知道它不是正确的数据类型,所以它在下一个循环周期将读取输入放回缓冲区,但是无效输入仍然在缓冲区中,这将导致scanf()再次失败,因为缓冲区没有'被清空了,这个循环一直持续着。

为了解决这个问题,您可以使用scanf()的返回值,这将是读取的成功输入的数量,但是您需要通过刷新缓冲区来丢弃无效输入以避免无限循环,当按下enter键时刷新输入缓冲区,您可以使用getchar()功能暂停获取输入,这需要您按下enter因此,丢弃无效输入,请注意,无论您输入的数据类型是否正确,都不会按enter键两次,因为newline character仍然在缓冲区中。在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;
}