C语言中scanf读取字符无法按预期工作

7

最近我在我的电脑上运行了一个C程序。其中有一个for循环,可以扫描一些字符d。这个for循环运行了3次。在每次运行时,它会打印出运行的计数,然后扫描字符d的值。该程序如下:

#include<stdio.h>

int main(){
    int f;
    char d;
    for(f=0;f<3;f++){
        printf("Choice %d\n", f);
        scanf("%c", &d);
    }
    return 0;
}

现在的问题是,当我运行程序时,如果f为1,for循环会跳过scanf部分。现在如果我按照以下方式更改代码:
#include<stdio.h>

int main(){
    int f;
    int d;
    for(f=0;f<3;f++){
        printf("Choice %d\n", f);
        scanf("%d", &d);
    }
    return 0;
}

现在程序运行良好,对于for循环的每次迭代,都会执行scanf。

那么问题似乎出在哪里呢?我的意思是,当d是int类型时,它可以很好地工作,但当d是char类型时,它不能正确工作。


4
你为什么不阅读scanf()的手册呢?无论你如何修复,你都使用它的方式是错误的。 - Iharob Al Asimi
@Jared Burrows 你能否再解释详细一些? - Vivek Sasidharan
你正在使用循环遍历 scanf 并且连续三次读取到同一个变量中。 - Jared Burrows
这只是我正在编写的一个更大程序的一部分,其中for循环包含更多代码。我只是在这里发布了有问题的部分。 - Vivek Sasidharan
@chux 哦,我没有给这个标题,肯定是有人改了它。 - Vivek Sasidharan
显示剩余4条评论
2个回答

34

你需要进行更改

scanf("%c", &d);
to
scanf(" %c", &d);
       ^
       |
否则,scanf() 将会考虑之前输入的ENTER按键。
注意:
  1. ENTER按键产生一个\n,而这个是%c格式指定符的有效输入。在%c前面添加一个空格可以告诉scanf()忽略所有前导类似空格的输入(包括之前存储的\n),并读取来自stdin的第一个非空格字符。

  2. 至于%d格式指定符,它会消耗(并忽略)任何数字输入之前的前导类似空格的输入,所以第二种情况没有任何问题。


哦,谢谢回复,它像魔法一样奏效了。为什么我需要这样做呢?我的意思是为什么要加一个空格? - Vivek Sasidharan
@Vivek 更新了我的答案。 - Sourav Ghosh
"\n is not a valid input for %d specifier" 这句话是误导性的。因为 "\n" 是有效的 "%d" 输入,与 "%c" 不同的是,"%d" 首先会消费前导空格(包括 '\n'),然后再继续扫描数值输入。 - chux - Reinstate Monica
@chux 感谢您的建议。已进行更新。请您审核。 - Sourav Ghosh

3
问题在于当你输入字符scanf("%c", &d);时,你按下了回车键。该字符被scanf消耗掉,而换行符留在标准输入流(stdin)中。当下一次调用scanf(使用%c)时,它会看到\n字符在stdin中,然后将其消耗掉,因此不会等待更多的输入。
为了解决这个问题,请修改:
scanf("%c", &d);

to

scanf(" %c", &d);
//    ^Note the space before %c

使用 %c 前的空格指示 scanf 扫描任意数量(包括零个)的空格字符,并在遇到非空格字符时停止扫描。标准引用如下:

7.21.6.2 fscanf函数

[...]

  1. 由空格字符组成的指令通过读取输入直到第一个非空格字符(未读取)或者无法再读取更多字符来执行。该指令永远不会失败。
使用 %d 的原因是 %d 格式说明符自动跳过空格字符,因为 \n 是一个空格字符,所以 %d 不会扫描它。再次引用标准如下:

7.21.6.2 fscanf函数

[...]

  1. 输入的空格字符(由 isspace 函数指定)将被跳过,除非规范中包含 [cn 指定符。284

感谢您的详细解释。 - Vivek Sasidharan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接