【问题标题】:Why does scanf enter a loop when I input a character?为什么我输入字符时scanf会进入循环?
【发布时间】:2021-06-17 18:54:49
【问题描述】:

我必须完成一个大学项目,我的部分代码行为异常。

该部分的目标是获取用户输入的整数并将其存储在一个变量中,以便我以后可以使用它,但是如果用户输入一个字符,我必须再次询问该数字。

我使用scanf 函数获取用户输入并将其放入while 循环中,以在输入无效时不断请求输入。

问题在于,当用户输入字符时,代码会崩溃并开始运行while 循环,而不会在scanf 中停止以获取用户输入。 循环条件始终为真是有道理的,但奇怪的是它不会停止读取新输入。

我解构了我的代码,以便复制问题以使其更易于调试。 我知道有一些无用的变量,但在我的原始代码中它们很有用,我只是将它们保留在那里以使其看起来与原始代码相似。 我只能使用scanf 来获取用户输入,尽管我知道他们,但在这个项目中我只被允许使用 scanf。我不能使用scanf的格式来获取字符,这个项目只允许使用数字类型。

C11 是我们在类中使用的标准版本。

如果这个问题的解决方案很愚蠢,我很抱歉,我不擅长 C,而且这个学期我遇到了一些困难......

提前致谢。

    while (!verification) {
        printf(">>>"); //write values in here
        check = scanf("\n%d", &var); //input a number and store the number of valid inputs
        if (check) verification = 1; //if the input is a number then the while condition should turn to false with this statement
        printf("var = %d, check = %d, verification = %d\n", var, check, verification); //printing all variables
    }

【问题讨论】:

  • 我建议将scanf("\n%d", &var) 更改为scanf("%d", &var)。格式说明符%d 将自动删除任何前导空格。
  • “如果用户输入了一个字符,我必须再次询问该数字。” 该字符保留在输入缓冲区中,直到您采取措施将其删除。如果某个字符在某些上下文中无法处理,那么scanf 不会将其丢弃。请考虑使用fgets(),后跟sscanf()strtol()。否则有duplicate questions 围绕如何清除输入 - 这是一个非常常见的问题。
  • "只能使用scanf来获取用户输入,尽管知道他们,在这个项目中我只允许使用scanf。我不能使用scanf' s 格式来获取字符,此项目中只允许使用数字类型。” 我不明白如何可能 删除阻止输入的不需要的非数字字符, 当scanf("%d", ...) 是唯一允许的输入方式时。

标签: c while-loop scanf


【解决方案1】:

如果用户没有输入整数,那么在调用 scanf 之后,输入流中会留下字符。因此,您需要在下一次尝试读取整数之前读取到行尾。否则 scanf 将尝试一次又一次地读取相同的非整数字符。这是一个例子:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int ch, i, n;

    n = scanf("%d", &i);
    while (n == 0) {
        fprintf(stderr, "wrong input, integer expected\n");
        do {
            ch = getchar();
        } while ((ch != EOF) && (ch != '\n'));
        n = scanf("%d", &i);
    }
    if (n == 1) {
        printf("%d\n", i);
    } else { /*n == EOF*/
        fprintf(stderr, "reading input failed\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}

【讨论】:

  • 非常感谢,我和老师谈了getchar函数,他回答说只要指定思路就可以使用。有效!谢谢!
  • @RicardoQuintela 我很高兴为您提供帮助。您可以通过单击复选标记将答案标记为已接受。
【解决方案2】:

不要使用scanf() 来读取用户的输入。

它实际上只用于读取已知为特定格式的数据,而来自用户的输入...通常不是。

虽然您确实检查了scanf("%d") 的返回值,并且可以解决输入不是数字的情况,但如果输入是空行或后面跟着数字,您仍然会遇到问题别的东西 (123 foobar)。

如果是空行,scanf()继续等待非空白字符。这可能会令人困惑,因为用户会期望按 Enter 来执行某事

如果数字后面有尾随内容,则该内容将保留在输入缓冲区中,下一次您读取某些内容时,它会被读取。这可能再次令人困惑,因为用户很少期望他们对一个问题的输入也可以作为对另一个问题的输入。

相反,使用fgets()getline() 阅读整行,然后运行sscanf()strtol()。这更加直观,并且避免了scanf() 仅部分消耗输入行(或消耗多行)导致的断开连接。另见例如scanf() leaves the new line char in the buffer

在这里,使用 getline()(POSIX,即使不在标准 C 中。如果 getline() 不可用,则使用 fgets()):

#include <stdio.h>

int main(void)
{
    char *line = NULL;
    size_t len = 0;
    int result;
    printf("Please enter a number: ");
    while (1) {
       if (getline(&line, &len, stdin) == -1) {
           /* eof or error, do whatever is sensible in your case */
           return 1;
       }
       if (sscanf(line, "%d", &result) != 1) {
           printf("That didn't seem like number, please try again: ");
           continue; 
       } 
       break;
    }
    printf("You entered the number %d\n", result);
}

【讨论】:

  • @chqrlie,不,分号没有理由
  • 注意:getline() 不在标准 C 库中。
  • 这是一个大学练习,OP 声明 “我只能使用scanf 来获取用户输入,尽管我知道他们,但在这个项目中我只能使用scanf。我无法使用scanf的格式获取字符,本项目只允许使用数字类型。”
  • @WeatherVane,是的,这是一个很好的机会让他们意识到,并不是他们在大学里所教和要求的一切都是明智的;并练习与老师讨论为什么其他方式会更好。
  • @WeatherVane,请注意,严格遵守该限制,通常的“循环 getchar() 直到看到换行符”的解决方案也已失效,但可以替换为 scanf() 读取单个字符,我想。
【解决方案3】:

问题是你必须在转换失败时丢弃有问题的输入。

这里是一个简单的解决方案,只使用scanf() 按照说明:

#include <stdio.h>

int main() {
    int n;

    for (;;) {
        printf("Enter an number: ");
        switch (scanf("%d", &n)) {
        case 1:
            /* successful conversion */
            printf("The number is %d\n", n);
            return 0;
        case 0:
            /* conversion failure: discard the rest of the line */
            scanf("*[^\n]");  // discard characters before the newline if any
            scanf("*1[\n]");  // optional: discard the newline if present
            printf("Invalid input. Try again\n");
            continue;
        case EOF:
            /* input failure */
            printf("Premature end of file\n");
            return 1;
        }
    }
}

【讨论】:

    猜你喜欢
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 2018-11-06
    相关资源
    最近更新 更多