【问题标题】:Endless while loop when input a string to a variable that expected integer value将字符串输入到期望整数值的变量时出现无限循环
【发布时间】:2021-12-28 18:19:11
【问题描述】:

我的C代码如下

int main() {
    int userInput = 0;

    while (userInput != 4) {
        printf("Enter a number : ");
        scanf("%d", &userInput);
    };
    return 0;
}

这通常在输入整数值时起作用。但是当输入 一个字符串值 时,它不会再次询问输入。它进入一个无限循环,打印“输入数字”短语。然后,我尝试了如下代码。

int main() {
    int userInput = 0;

    while (userInput != 4) {
        userInput = 0;             // reset the userInput value
        printf("Enter a number : ");
        scanf("%d", &userInput);
    };
    return 0;
}

即使这样也没有解决我的问题。为什么会这样?怎么解决?

【问题讨论】:

  • 你应该检查scanf的返回值是否成功。如果输入与格式字符串不匹配,它会保留在流中,并且会被一遍又一遍地读取(并失败)。
  • 您的%d 格式只查找整数。如果它看到一个非整数字符,它将停止。所以它只是一遍又一遍地看着同一个角色。你最好先读一整行,然后再看你读到的内容。
  • 这能回答你的问题吗? Entering a character instead of integer
  • trueThari,请注意,您输入的不是字符串,而是文本行,可能带有终止符'\n'。 C 中的 string 是带有终止 null 字符 的字符数组。

标签: c while-loop integer scanf


【解决方案1】:

您需要从无效数据中释放输入缓冲区。类似于以下内容。

do
{
    printf("Enter a number : ");
    if ( scanf("%d", &userInput) != 1 )
    {
        scanf( "%*[^\n]" );
        userInput = 0;
    }
} while ( userInput != 4 );

另一种方法是使用函数fgets读取字符数组中的整个字符串,然后使用strtol将其转换为整数并检查转换是否成功。

【讨论】:

  • 你能解释一下“%*[^\n]”的作用吗?
  • @trueThari 表示读取输入缓冲区中的所有符号,直到遇到换行符'\n',但不要将它们存储在数组中。
【解决方案2】:

“这通常在输入整数值时起作用。但是当输入字符串值时,它不会再次询问输入。”

如果scanf() 未转换数据扫描,则输入流(在本例中为stdin)不高级。当再次调用scanf() 时,它将尝试从相同的错误输入中扫描和转换相同的数据,并得到相同的结果。这就是导致无限循环的原因。设置 `scanf() 转换数字字符时输入字母字符总是会失败。

好消息是scanf() 返回一个值,指示有多少项目已成功转换。 alpha 使用 %d 格式说明符扫描的输入应该会导致转换零项。使用scanf() 的代码应始终检查它的返回值:

int num_converted = scanf("%d", &userInput);
if(num_converted != 1) 
{
     //handle error 
     ...
}

顺便说一句,scanf() 被许多人视为sub-optimal method for handling user input。例如

"...它会告诉你它是成功还是失败,但只能告诉你它失败的大致位置,而不是如何或为什么失败。你 几乎没有机会进行任何错误恢复。”
(jamesdlin)。

考虑基于使用fgets() 的替代方法。

以下将整个输入行读入缓冲区,消除不需要的空白并验证输入。只有这样它才会将输入缓冲区转换为指定的类型...

int main(void) {
    int userInput = 0;
    char inBuf[20] = {0};
    
    printf("Enter a number : ");
    //int num = scanf("%d", &userInput);
    while (fgets(inBuf, sizeof inBuf, stdin)) {
        inBuf[strcspn(inBuf, "\r\n")] = 0;//remove unwanted white space
        if(digits_only(inBuf))//example validation for numeric only input
        {
            userInput = atoi(inBuf);
            printf("\n%d entered, and converted!\n\nctrl-c to exit\n...Or enter a number : \n", userInput);
        }
        else
        {
            printf("\n%s contains non-numeric characters, it cannot be converted.\n\nctrl-c to exit\n...Or enter a number : \n", inBuf);
        }
    };
    return 0;
}

//test for numeric only input   
//(note that other validations can be coded with expansions 
//to accommodate float or double, alpha only, etc.)    
bool digits_only(const char *in)
{
    while(*in)
    {
        if(!isdigit(*in)) return false;
        in++;
    }
    return true;
}

【讨论】:

    猜你喜欢
    • 2019-01-14
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 2013-12-30
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多