当格式字符串末尾有换行符时,为什么scanf需要两次输入?

26
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *method1(void)
{
    static char a[4];
    scanf("%s\n", a);
    return a;
}

int main(void)
{
    char *h = method1();
    printf("%s\n", h);
    return 0;
}
当我运行上面的代码时,提示框会要求我输入两次(但我的代码中只使用了scanf一次)。为什么会这样呢?
(我输入了'jo';它要求我再次输入,所以我又输入了'jo'。然后它只打印出了'jo'一次。)

你得到了什么输出? - Aswin Murugesh
这是一个非常短的数组。你输入了太多的数据吗? - Jonathan Leffler
我输入jo。 它要求另一个输入。 然后我再次输入jo。 然后它才打印出一次jo。 - joy
我知道这只是一小段代码,但你应该始终检查像scanf和其他转换函数的结果。 - Jens
这回答解决了你的问题吗?在scanf()格式字符串中添加尾随空格有什么影响? - Andreas Wenzel
7个回答

27

从我的scanf手册页面上可以看到:

格式字符串中的空白(如空格、制表符或换行符)会匹配输入中任意数量的空白,包括零个。其他所有字符只匹配它们自己。

因此,使用scanf ("%s\n", a)将扫描一个字符串后面跟着可选的空白。由于在第一个换行符之后可能会有更多的空格,因此scanf不会在第一个换行符之后结束,而是继续查找下一个字符。您会注意到,您可以输入任意数量的换行符(或制表符或空格),scanf仍然会等待读取更多内容。

然而,当您输入第二个字符串时,空白序列被分隔开并且扫描停止。

使用scanf ("%s", a)来避免扫描尾随的空白。


13

你需要从scanf的字符串格式中删除\n。应该是这样的:

scanf("%s",a);

编辑:解释

%s 的意思是,scanf 读取输入字符直到获取一个分隔符,这个分隔符应该是空格、制表符或换行符 (\n),所以第一个回车符作为 "%s" 的分隔符被获取,将 "\n" 添加到字符串格式 "%s\n" 中意味着 scanf 将等待 2 个换行符,第一个换行符与 "%s" 的分隔符有关,第二个换行符与字符串格式中的 \n 有关。


2
你走在正确的道路上,但是你没有说 scanf 会一直读取空格,直到遇到一个非空格字符才停止。你可以在输入一个非空格字符之前输入许多换行符(还有空白或制表符),从而停止 scanf。这是更喜欢 fgets()sscanf() 而不是文件 I/O 变体的 scanf() 的另一个原因。 - Jonathan Leffler
1
你对scanf等待两个换行符的推断是错误的。所有输入的换行符(即使超过两个)都会被格式中的单个\n扫描,任何交错的空格和制表符也是如此。请阅读C标准或手册页面中的scanf规范。 - Jens

0

从scanf格式中删除\n,并提供输入,它将根据给定的输出一次显示输出。


错误的斜杠。此答案对之前的回答没有任何贡献。 - Nathan Tuggy

0

你可以使用以下任意一种方式来避免上述问题: scanf("%s",a); 或者 scanf("\n%s",a);


0
尝试这样做:在scanf中不要使用\n,它不会两次询问,并且有时可能会显示错误。
你的代码: scanf("%s\n", a);
尝试在scanf上使用这个: scanf("%s", a);

其他答案在8年前已经提到了这一点,这并没有增加任何新内容。 - Blastfurnace

-1
不要在scanf stdio函数中使用转义序列。
     scanf ("%s", a);

3
这篇答案中没有解释为什么这么做,以及如果你这么做会发生什么。这并没有为Mohamed所写的答案或被采纳的答案增加任何内容。 - Jonathan Leffler

-1

使用gets()或fgets()代替...或者使用scanf("%[^\n]s",a);


使用scanf将输入存入数组,直到遇到空格为止。因此,请使用%[^\n]s格式说明符。或者不要使用scanf,而是选择fgets()或gets()函数。 - Darshan Shah
3
"%[^\n]s"由两个指示符组成:%[^\n] 匹配(并存储)一个或多个非'\n'字符,或者因立即遇到'\n'而失败,并且 s匹配字面上的's'并将其丢弃,或者失败并将非's'字符推回到stdin。第一个指示符会在连续尝试中失败,因为'\n'不是's',所以'\n'将直接推回到stdin,并成为第一个遇到的字符。请自行查看:char a[64]; int n = scanf("%[^\n]s", a); assert(n == 1); n = scanf("%[^\n]s", a); assert(n == 1); - autistic
1
我的建议是阅读fscanf手册,以便您可以澄清关于%[指令和%s指令的困惑。 - autistic

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