【问题标题】:how to stop repeated invalid answers for char in c?如何停止 c 中 char 的重复无效答案?
【发布时间】:2016-04-26 23:57:44
【问题描述】:

我正在构建一个长程序,需要在 if/else 语句中使用典型的“y/n”字符函数,它工作正常,但如果用户输入无效的内容,它将重复我的“无效答案”字符串等于他们输入的字符数。我尝试使用“%1s”而不是 %c,但这并不能阻止失控输入。

#include<stdio.h>

int main()
{
 printf("Welcome.I can predict the future\n"
     "I learned this gift from someone in the future.\n"
     "A bright creature with green eyes taught me how.\n"
 "It appeared to me on a Sunday without enthusiam\n"
     "and told me I would end up trapped in a computer,\n"
 "and there was nothing I could do about it.\n"

 "It was really cruel of it to do that.\n"
 "I could have enjoyed the rest of my days\n"
 "without being depressed having known that...\n"
 "I also didn't need to know so many other things I\n"
 "now have learned.\n\n"

 "Having said this, would you like me to predict you\n"
     "future?y/n\n");

 char ansr;
 scanf("%1s", &ansr);


 while (ansr != 'y' && ansr != 'n'){

 printf("Invalid answer, Please try again.");
 scanf("%1s", &ansr);
 }

 if ( ansr == 'y') {
 printf("You've been warned.\n\n");
 }
 else if ( ansr == 'n') {
 printf("Goodbye Then.\n\n");
 }




 return 0;

 }

【问题讨论】:

  • char ansr[2]; scanf("%1s", ansr); while (*ansr != 'y' &amp;&amp; *ansr != 'n'){
  • 使用:char ansr; scanf("%1s", &amp;ansr);是错误的; %1s 需要一个指向 2 个字符的指针,一个用于字符,一个用于字符串末尾的 null。也许你想要char answer; if (scanf(" %c", &amp;answer) == 1) { …OK… } else { …EOF or error… }。注意格式字符串中的前导空格,并且没有尾随空格或空格;两者都很重要。

标签: c input


【解决方案1】:

首先,您不想将%1schar 一起使用,因为此格式说明符需要一个数组。在ansr的内存位置写入1个字符后,它将在下一个内存位置写入一个空字节。这导致了未定义的行为。坚持使用%c

要清除多余的字符,您需要在循环中使用getchar 来读取字符,直到找到换行符为止。这将刷新缓冲区。

while (ansr != 'y' && ansr != 'n') {
    printf("Invalid answer, Please try again.");
    while ( getchar() != '\n');
    scanf("%c", &ansr);
}

输出:

...
Having said this, would you like me to predict you
future?y/n
bogus
Invalid answer, Please try again.wrong
Invalid answer, Please try again.yep
You've been warned.

【讨论】:

    【解决方案2】:

    要处理输入中的字符串,您可以尝试从标准输入读取到ansr 缓冲区,如下所示,然后进行字符串比较。通过用%*[^\n] 丢弃stdin 中的其余内容,扫描不受空格或多个字符的影响,您将获得所需的y/n 字符。也不要忘记你的右大括号,并在main 中返回零。

    #include <stdio.h>
    #include <string.h>
    #define buffLen 32
    
    int main() {        
    
        char ansr[buffLen] = "";
    
        printf("...would you like me to predict your future? (y/n) \n");
    
        while (strcmp(ansr, "y") != 0 && strcmp(ansr, "n") != 0){
    
            // Read the string, and throw away the rest up to the newline char.
            scanf("%s%*[^\n]", &ansr);
    
            if (strcmp(ansr, "y") == 0) {
                printf("You've been warned.\n");
            } else if (strcmp(ansr, "n") == 0) {
                printf("Goodbye Then.\n");
            } else {
                printf("Invalid answer, Please try again.\n");
            }
        }
    
        return 0;
    }
    

    编辑: cmets 中有一个很好的建议,即使用 do-while 循环,以免我们用虚拟的东西初始化缓冲区 ansr,因为 do 块初始化在评估条件之前缓冲。我喜欢这个,因为我很少考虑使用这些,但这是何时使用的一个很好的例子......

    #include <stdio.h>
    #include <string.h>
    #define buffLen 32
    
    int main() {
    
        char ansr[strLen];
    
        printf("...would you like me to predict your future? (y/n) \n");
    
        do {
            // Read the string, and throw away the rest up to the newline char.
            scanf("%s%*[^\n]", &ansr);
    
            if (strcmp(ansr, "y") == 0) {
                printf("You've been warned.\n");
            } else if (strcmp(ansr, "n") == 0) {
                printf("Goodbye Then.\n");
            } else {
                printf("Invalid answer, Please try again.\n");
            }
        } while (strcmp(ansr, "y") != 0 && strcmp(ansr, "n") != 0);
    
        return 0;
    }
    

    【讨论】:

    • 您可能希望将其转换为 do-while 循环。如所写,该程序可能在第一次出现未定义行为或根本无法运行,因为它在 ansr 的内容初始化之前调用了 strcmp()
    • 哎呀,不错,我打算初始化它。
    • 缓冲区溢出,这个程序很容易发现,在scanf调用中,给它一个长度,否则容易受到攻击。
    • 关于溢出的好点,我们可以用像scanf("%31s%*[^\n]", &amp;ansr);这样的神奇数字来防止这种情况发生
    • 这是一个非常有趣的回应,尽管现在我会选择最上面的,因为我更好地理解它....你能分解“%*[^\n]”吗?我,就每个角色的作用而言?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 2018-09-19
    • 2018-12-08
    • 1970-01-01
    相关资源
    最近更新 更多