为什么scanf(“%d”,)不消耗’\ n’? 而scanf(“%c”)呢?

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

大多数转换说明符跳过前导空格,包括换行符,但%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; } 

交换两个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行为与scanf '\n'不同?

从马的嘴里 :

7.21.6.2 fscanf函数


5由白色空格字符组成的指令通过读取第一个非空白字符(仍未读取)的输入来执行,或者直到不再能读取字符为止。 该指令永远不会失败。

7作为转换规范的指令定义了一组匹配的输入序列,如下面针对每个指定器所述。 转换规范按以下步骤执行:

8跳过输入空白字符(由isspace函数指定), 除非规范包含[cn指定 isspace284)

9从流中读取输入项,除非该规范包含n指定者。 输入项被定义为输入字符的最长序列,其不超过任何指定的字段宽度,并且是匹配输入序列的前缀或前缀。 285)输入项目保持未读后的第一个字符(如果有)。 如果输入项的长度为零,则指令的执行失败; 除非文件结束,编码错误或读取错误阻止了流的输入,否则此条件是匹配失败,在这种情况下,它是输入失败。


284)这些空白字符不计入指定的字段宽度。
285)fscanf将最多一个输入字符推回到输入流上。 因此,strtod,strtol等可接受的一些序列对于fscanf是不可接受的。

强调我加入了。

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

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

 scanf(" %c", &ch); 

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

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

所以,如果我这样做:

 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 

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

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

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

这是因为空格永远不能是整数,但空格是由字符组成的。 如果你特别想要一个角色尝试类似的东西

 scanf("%c", &ch ); while(isspace(c)) scanf("%c" , &ch); 

或者使用!isalnum()如果你只允许字母和数字或!isalpha()只用于字母。

我不是专家,但我发现这样做:

 fflush(stdin); 

每次扫描后都有帮助..

如:

 scanf("%c", &ch); fflush(stdin);