10

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

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

交换两个scanfs 和 (commented) 可以解决问题,getchar否则'\n'第一个插入的 s 将被第二个scanfwith消耗%c。我在 linux 和 windows 上都在 gcc 上进行了测试,行为是一样的:

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

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

4

4 回答 4

12

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

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'如果您要正确使用它,您必须使用它。

于 2012-11-07T18:13:04.543 回答
10

马口中

7.21.6.2 fscanf 函数

...
5 由空白字符组成的指令通过读取输入执行,直到第一个非空白字符(仍然未读取),或者直到无法读取更多字符。该指令永远不会失败。
...
7 作为转换规范的指令定义了一组匹配的输入序列,如下文对每个规范的描述。转换规范按以下步骤执行:

8 输入空白字符(由isspace函数指定)被跳过,除非规范包括 a [c或说明n284)

9 从流中读取输入项,除非规范中包含说明n符。输入项被定义为输入字符的最长序列,它不超过任何指定的字段宽度,并且是匹配输入序列的前缀或匹配输入序列的前缀。 285) 输入项之后的第一个字符(如果有)保持未读状态。如果输入项的长度为零,则指令执行失败;这种情况是匹配失败,除非文件结尾、编码错误或读取错误阻止了来自流的输入,在这种情况下,它是输入失败。
284)这些空白字符不计入指定的字段宽度。
285) fscanf 将最多一个输入字符推回输入流。因此,一些strtod、strtol等可以接受的序列,对于fscanf来说是不能接受的。

重点是我加的。

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

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

scanf(" %c", &ch);
于 2012-11-07T19:02:27.153 回答
2

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

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

或者!isalnum(),如果您只想允许字母和数字或!isalpha()仅允许字母,请使用。

于 2012-11-07T18:51:42.487 回答
-2

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

fflush(stdin);

在每次 scanf 帮助之后..

如:

scanf("%c", &ch);
fflush(stdin);
于 2012-11-07T18:27:22.887 回答