为什么scanf("%d",[...])不消耗'\n'?而scanf("%c")呢?

Ale*_* S. 10 c scanf format-specifiers

在这里,我在接受的答案中看到了这个陈述:

大多数转换说明符都跳过前导空格,包括换行符但%c不跳过.

对我来说,不清楚这种不同行为的基本原理,我会期待一个统一的(例如总是跳过或从不).

我用这样的一段C代码遇到了这种问题:

#include "stdio.h"

int main(void){

    char ch;
    int actualNum;

    printf("Insert a number: ");
    scanf("%d", &actualNum);
    // getchar();

    printf("Insert a character: ");
    scanf("%c", &ch);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

交换两个scanf小号解决了问题,以及在(注释)getchar,否则'\n'该第一插入将由所述第二消耗scanf%c.我在linux和windows上测试了gcc,行为是一样的:

gcc(GCC)4.7.2 20120921(Red Hat 4.7.2-2)
版权所有(C)2012 Free Software Foundation,Inc.
这是免费软件; 查看复制条件的来源.没有保修; 甚至不适用于适销性或特定用途的适用性.

所以我的问题是:为什么%d%c行为不同WRT '\n'scanf

Mik*_*ike 12

这是一贯的行为,你只是想错了.;)

scanf("%c", some_char); // reads a character from the key board.
scanf("%d", some_int);  // reads an integer from the key board.
Run Code Online (Sandbox Code Playgroud)

所以,如果我这样做:

printf("Insert a character: ");
scanf("%c", &ch);                // if I enter 'f'. Really I entered 'f' + '\n'
                                 // scanf read the first char and left the '\n'
printf("Insert a number: ");
scanf("%d", &actualNum);      // Now scan if is looking for an int, it sees the '\n'
                              // still, but that's not an int so it waits for the 
                              // the next input from stdin
Run Code Online (Sandbox Code Playgroud)

在这种情况下,并不是它自己消耗换行符.试试这个:

char ch;
char ch2;
printf("Insert a character: ");
scanf("%c", &ch);
printf("Insert another character: ");
scanf("%c", &ch2); 
Run Code Online (Sandbox Code Playgroud)

它将"跳过"第二个,scanf()因为它在那时读取'\n'.scanf()是一致的,你必须消费,'\n'如果你要正确使用它.


Joh*_*ode 10

马的嘴里:

7.21.6.2 fscanf函数

...
5由白色空格字符组成的指令通过读取第一个非空白字符(仍未读取)的输入来执行,或直到不再能读取字符为止.该指令永远不会失败.
...
7作为转换规范的指令定义了一组匹配的输入序列,如下面针对每个指定器所述.A转换SPECI音响阳离子在下面的步骤执行:

8输入的空白字符(如由编SPECI音响isspace功能)被跳过,除非SPECI音响阳离子包括[,cnSPECI音响ER. 284)

9从流中读取输入项,除非该规范包含n特定的指定项.输入项被定义为输入字符的最长序列,其不超过任何指定的字段宽度,并且是匹配输入序列的前缀或前缀. 285) 输入项目保持未读后的第一个字符(如果有).如果输入项的长度为零,则指令的执行失败; 该条件匹配的失败,除非最终OF-音响文件,编码错误,或读出错误从流,在这种情况下它是一个输入故障防止输入.
284)这些空白字符不计入指定的字段宽度.
285)fscanf将最多一个输入字符推回到输入流上.因此,strtod,strtol等可接受的一些序列对于fscanf是不可接受的.

强调我加入了.

空格不是有效整数字符串的一部分,因此%d转换说明符跳过任何前导空格是有意义的.但是,空格本身可能是有效的,因此%c转换说明符跳过它是有意义的.

根据上述第5条,如果在%c指令之前的格式字符串中放置一个空格,则将跳过所有前导空格:

scanf(" %c", &ch);
Run Code Online (Sandbox Code Playgroud)