【问题标题】:scanf not working on invalid inputscanf 无法处理无效输入
【发布时间】:2016-11-11 15:23:29
【问题描述】:

在第一个scanf() 中输入字符时,第二个不运行。 getchar() 也不适用于重试输入。它会跳过输入你想再玩一次吗? (Y/N)? 似乎your_choice 应该拿走该角色并在之后检查它,但该角色实际上是由ch 拿走的。是什么导致它像这样工作以及如何解决这个问题。我尝试重新初始化变量,但不起作用。

#include <stdio.h>

void choice(int);

int main() {
    char ch;
    int random, your_choice;

    do {
        srand(time(NULL));
        system("cls");
        printf("** 0 is for Rock **\n");
        printf("** 1 is for Scissors **\n");
        printf("** 2 is for Lizard **\n");
        printf("** 3 is for Paper **\n");
        printf("** 4 is for Spock **\n");

        printf("\nEnter your choice here:");
        scanf("%d", &your_choice);

        random = rand() % 5; //random number between 0 & 4
        if ((your_choice >= 0) && (your_choice <= 4)) {
            //choice printer omitted for this post

            if ((random == ((your_choice + 1) % 5)) || (random == ((your_choice + 2) % 5)))
                printf("\n\n... and you win!!!\n");
            else if ((random == ((your_choice + 3) % 5)) || (random == ((your_choice + 4) % 5)))
                printf("\n\n... and you lose!!!\n");
            else if (random == your_choice)
                printf("\n\nUnfortunately, it's a tie!\n");
        } else
            printf("\nWell, this is wrong! Try again with a number from 0 to 4!!\n");

        printf("\nWould you like to play again? (Y/N)?: ");
        scanf(" %c", &ch);

    } while (ch == 'y' || ch == 'Y');

    return 0;
}

【问题讨论】:

  • 对于初学者,请在第二个scanf 中的%c 之前占用您的空间
  • 查看scanf的返回值。如果出现解析错误,则无效输入会留在输入缓冲区中,因此您必须先将其删除,然后再尝试scanf 相同的数据。如果你忽略scanf 的返回值并且不对它的解析错误做出反应,你通常会得到一个在无效输入上表现完全出乎意料的程序。
  • @hyde 在打印 ch 时,它给出了在选择中输入的值。
  • @jnbbender:绝对不是!空格告诉scanf() 忽略待处理的空格,这是在读取第一个输入后跳过仍存在于标准输入缓冲区中的换行符所必需的。

标签: c debugging scanf stdin


【解决方案1】:

如果用户输入了无法转换为数字的字符,scanf("%d", &amp;your_choice); 返回 0,your_choice 保持不变,因此未初始化。行为未定义。

您应该对此进行测试并以这种方式跳过有问题的输入:

    if (scanf("%d", &your_choice) != 1) {
        int c;
        /* read and ignore the rest of the line */
        while ((c = getchar()) != EOF && c != '\n')
            continue;
        if (c == EOF) {
            /* premature end of file */
            return 1;
        }
        your_choice = -1;
    }

解释:

  • scanf() 返回成功转换的次数。如果用户键入一个数字,它会被转换并存储为your_choicescanf() 返回 1,如果用户输入不是数字的内容,例如AAscanf() 会将违规输入留在标准中输入缓冲区并返回 0,最后如果到达文件末尾(用户在 windows 中输入 ^Z 或在 unix 中输入 ^D),scanf() 返回EOF

  • 如果输入未转换为数字,我们输入if 语句的主体:输入以getchar() 一次消耗一个字节,直到文件结尾或换行阅读。

  • 如果getchar()返回EOF,我们已经读取了整个输入流,不需要提示用户进行更多输入,您可能希望在返回错误代码之前输出错误消息。

  • 否则,将your_choice 设置为-1,这是一个无效值,因此代码读取会报错并提示进一步输入。

读取和丢弃违规输入是必要的:如果您不这样做,下一个输入语句scanf(" %c", &amp;ch); 将读取违规输入的第一个字符,而不是等待用户输入以响应Would you like to play again? (Y/N)?: 提示。这是对您观察到的行为的解释。

【讨论】:

  • return 1; 到底是做什么的?
  • main退出并结束程序。通过检查errorlevel,(在 Windows 中)可能调用您的程序的批处理文件可以捕获返回值。
  • @nAiN 如果您首先输入带有fgets 的字符串,然后将sscanf 应用于该字符串(检查这些函数的返回值),则更容易管理错误输入。如果输入不正确,您只需转储该行并重试。
  • @nAiN:使用fgets()sscanf() 是一个很好的建议。我希望 C 教程能更频繁地采用这种方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-24
  • 1970-01-01
  • 2021-09-16
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多