c - scanf 并非在每次循环迭代时都执行

标签 c for-loop printf scanf strcmp

我写一个程序是为了好玩(不是为了学校),我很难弄清楚为什么 scanf 函数没有在我的循环的每次迭代中执行 - 我玩过具有“for”循环和“while”循环。

我知道这取决于我如何编写 scanf 函数(即 scanf("%s", &variablename); VS scanf("%99[ ^\n]s", &variablename);) 有所不同,但我已经尝试了一切,我很绝望!

当我对来自 scanf 的输入执行 printf 检查时,在每次迭代中它每次迭代只接收一个字符串,所以如果我在我的输入中输入两个单词第一个输入,然后需要两次迭代来处理——每个一个词。这是我正在描述的代码段:

int main(void){
    int tries = 0;
    int score = 0;
    char question[100];
    char useranswer[100];
    const char *phrase = {"our favorite saying\0"};

    printf("\nQuestion #3 (10 points): What is our secret saying?\n");
        sleep(1);
        tries = 1;

    while (tries<=3){
        printf("YOUR ANSWER:");
        scanf("%s[^\n]", useranswer); 

        if(strncmp(useranswer, phrase, 15) != 0){
            printf ("Nope, try again!\n");
            printf("You have used %d out of 3 tries!\n", tries);
            if (tries == 2){
                printf("Here's your final hint:xxx...\n");
            }
            if (tries == 3){
            printf("You didn't get it. The answer is: our favorite saying!\n");
            }
            tries++;
        }   
        if (strncmp(useranswer, phrase, 15) == 0){
            printf("Damn, you're good.  Well done.\n");
            score += 10;
            break;
        }
    }   

这段代码的输出是:

Question #3 (10 points): What is our secret saying?
YOUR ANSWER:our favorite saying
Nope, try again!
You have used 1 out of 3 tries!
YOUR ANSWER:Nope, try again!
You have used 2 out of 3 tries!
Here's your final hint:xxx...
YOUR ANSWER:Nope, try again!
You have used 3 out of 3 tries!
You didn't get it. The answer is: our favorite saying!

(它只允许我输入一次,我输入了“我们最喜欢的一句话”。)

最佳答案

在评论中,您可以找到为什么 scanf 中的格式说明符不起作用。

另一种方法是使用 fgets相反,也许在一个辅助函数中处理读取用户输入时可能出现的一些极端情况:

#include <ctype.h>

char *read_line( char *buf, size_t n, FILE *pfin )
{
    ssize_t length = 0;
    int ch;

    if ( !buf || n == 0 )
        return NULL;
    /*  Consume trailing control characters, like '\0','\n', '\r', '\f'...
        but also '\t'. Note that ' ' is not skipped. */
    while ( (ch = fgetc(pfin)) != EOF  &&  iscntrl(ch) ) { }
    if ( ch == EOF )
        return NULL;
    /*  At least one char is printable  */
    *buf = ch;
    ++length;

    /*  Read from file till a newline or up to n-2 chars. The remaining chars
        are left in the stream buffer. Return NULL if no char is read.      */
    if ( fgets(buf + 1, n - 1, pfin) )
    {
        /*  Trim the string to the first control character                  */
        while ( !iscntrl(buf[length]) ) 
        {
            ++length;
        }
        buf[length] = '\0';       
    }
    return buf;
}

我也会更改以下逻辑。 OP 多次使用 strncmp(useranswer, phrase, 15),但是那个魔数(Magic Number) 15 小于 phrase 的大小,所以它最终只比较一个子串。

while ( tries <= 3 ) {
    printf("YOUR ANSWER:");
    if ( !read_line(useranswer, sizeof useranswer, stdin) ) {
        printf("Error: Unexpected end of input.\n");
        exit(EXIT_FAILURE);
    }
    if( strcmp(useranswer, phrase) == 0 ) {
        printf("Damn, you're good.  Well done.\n");
        score += 10;
        break;
    } else {
        printf ("Nope, try again!\n");
        printf("You have used %d out of 3 tries!\n", tries);
        if (tries == 2) {
            printf("Here's your final hint:xxx...\n");
        }
        if (tries == 3) {
            printf("You didn't get it. The answer is: our favorite saying!\n");
        }
        tries++;
    }
}


最后一点,我发现 phrase 的 OP 声明有点奇怪(可能是打字错误):

const char *phrase = {"our favorite saying\0"};
//            string literals are already ^^ null terminated...

虽然我们可以使用简单的数组声明,例如:

const char phrase[] = "our favorite saying";

还要考虑 sizeof phrase 在这两种不同情况下返回的值。


感谢 @chux 提供所有有值(value)的提示和有趣的链接:
https://stackoverflow.com/a/27729970/4944425
https://stackoverflow.com/a/28462221/4944425
感谢 @Dmitri 在他的评论中指出,一旦我们确定两个字符串都以 null 终止,我们就可以使用 strcmp 而不是 strncmp.

关于c - scanf 并非在每次循环迭代时都执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38087312/

相关文章:

c - pthread 条件不满足

c - 如何通过 llvm-c api 创建命名元数据?

javascript - Javascript 中的 For 循环与 while 循环

r - 迭代字符串 R 的字符

c - 逐个获取 vsnprintf() 输出

c - C语言printf中的%s和%d是什么意思?

添加两个 uint8_t 时的转换警告

c - 使用静态数组初始化常量结构对象

c - 反面打印

c - sprintf 缓冲区大小