程序陷入无限循环,无法弄清楚原因

时间:2017-09-07 18:27:05

标签: c

只是一个简单的程序,取10个整数,并告诉我哪个是最大的。这是我第一次使用C语言,尽管我之前使用过Java,Python和Ruby编程。如果输入字符而不是整数,它只会进入无限循环。它将当前变量设置为-8995460(或类似的东西),然后只是无限重复该广告。我只是在某个地方犯了一个愚蠢的错误,或者这是我对C不了解的事情?

int main(void)
{
    int counter = 0;
    int largest = 0;
    while (counter != 10) 
    { 
        int current;
        printf("%s", "Enter non-negative number: "); 
        scanf_s("%d", &current); 
        if ((current >= 0) && (isdigit(current)))
        {

            if (current > largest)
            {
                largest = current; 
            }
            counter++; 
        }
        else 
        {
            puts("Invalid number. Number must be positive. \n");
        }

    }
    printf("%d", largest);
}

3 个答案:

答案 0 :(得分:3)

您读取整数而不是字符。 isdigit检查字符是否为数字。如果current是一位数的数字,那么凭借一位数的数字肯定是一个数字"。

因此,isdigit函数将始终返回0(除非您输入与数字的当前字符编码值对应的十进制值),在C中等于false,所以你永远不会增加counter

对于您的问题,我会使用"%u"格式来scanf读取无符号的十进制数,并检查scanf返回的内容以查看输入是否正确。

请注意,如果输入不正确,它将留在输入缓冲区中,以便下次调用scanf,除非您将其删除。删除它的唯一可移植方法是逐字符号读取,直到您读取换行符。

答案 1 :(得分:1)

isdigit()用于检查字符的ASCII码是否为        0-9的数字的等效ASCII码。你应该只使用它        带有字符变量。

scanf(“%d”,& current)将始终读取整数到变量current。你不需要检查它。如果你    输入一个字符,你得到一个无限循环,因为scanf()    不能将字符存储在任何变量中,即它没有达到预期的效果。

你可以通过写作解决无限循环问题 scanf(“%s”,& str)其中str是字符数组(字符串)而不是scanf_s(“%d”,& current)。 现在你可以检查第一个字符是否是isdigit(str [0])。 如果不是,则跳过其他数字 使用atoi()函数将其转换为数字。

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#define BUF_LEN 256
int main()
{
    int counter = 0;
    int largest = 0;
    while (counter != 10) 
    { 
        char str[BUF_LEN];
        printf("%s", "Enter non-negative number: "); 
        scanf("%s", str); 
        if (isdigit(str[0]))//If first character is a digit then we asume that str contains a valid number. You should actually check it for all the characters in the string.
        {
            int current = atoi(str);//Convert string to integer (ASCII to Integer).
            if (current > largest)
            {
                largest = current; 
            }
            counter++; 
        }
        else 
        {
        puts("Invalid number. Number must be positive. \n");
        }

    }
    printf("%d", largest);
}

答案 2 :(得分:0)

As @SomeProgrammerDude pointed outisdigit检查字符是否为数字。你传给它一个整数。它会将该整数解释为一个字符,因此它会认为10是换行符,43+。如果你给它50它将会通过,因为它的字符是2

要检查scanf是否有整数,请不要检查current,因为如果scanf失败,它将包含垃圾。相反,请检查scanf的返回值,它会告诉您匹配了多少项。

int counter = 0;
int largest = 0;

// It's safer to check for X < BOUND than X != BOUND in case
// X happens to go over the BOUND.
while (counter < 10) { 
    int current;
    printf("%s", "Enter non-negative number: ");

    // What if `scanf` didn't get a number?
    if( scanf("%d", &current) != 1 ) {
        puts("That doesn't look like a number");
    }
    // What if it isn't positive?
    else if( current < 0 ) {
        puts("Invalid number. Number must be positive. \n");
    }
    // Now that all the error conditions have been checked...
    else {
        if (current > largest)
        {
            largest = current; 
        }
        counter++; 
    }
}
printf("%d", largest);

但仍有问题。如果得到无效的数字,代码将进入无限循环。这是many, many, many problems with scanf中的一个,特别是this one

问题是scanf不会读取行,它会读取尽可能多的内容。如果它读不出那么多,它就把它放在缓冲区上。如果scanf失败,则会在stdin上留下输入。当您再次阅读时,您将阅读相同的输入并再次失败。如果该行有任何额外输入,例如10 foo它会读取10,然后将foo留在缓冲区上,以便在下一次调用scanf时读取。 / p>

一般解决方案是逐行读取输入并解析该行。使用fgets读取行,sscanf扫描字符串。

int counter = 0;
int largest = 0;
char line[255];
while (counter < 10) {
    int current;

    printf("%s", "Enter non-negative number: ");
    fgets(line, sizeof(line), stdin);

    if( sscanf(line, "%d", &current) != 1 ) {
        puts("That doesn't look like a number");
    }
    ...and the rest is the same...
}

这可以保证你永远不会陷入无限循环。虽然如果输入大于line,它可能需要多次遍历fgets才能获得所有输入。