scanf() 格式字符串中尾随空格有什么影响?

What is the effect of trailing white space in a scanf() format string?

提问人:Vikas Verma 提问时间:10/21/2013 最后编辑:Jonathan LefflerVikas Verma 更新时间:6/11/2017 访问量:17084

问:

在此代码中,和之间有什么区别,其中区别在于格式字符串中的尾随空白?scanf("%d")scanf("%d ")

#include <stdio.h>

int main(void)
{
    int i, j;

    printf("enter a value for j ");
    scanf("%d  ",&j);
    printf("j is %d\n", j);
    printf("enter a value for i ");
    scanf("%d", &i);
    printf("i is %d\n", i);
    return 0;
}

当我在格式说明符后添加空格时,该函数实际上是如何工作的?scanf()scanf("%d ", &j);

c 扫描

评论


答:

0赞 Cloud 10/21/2013 #1

区别(虽然很明显)是不同的格式字符串。如果输入以下行:

"3  "

scanf()将成功返回。否则,这取决于您提供的输入。 实质上跳过空格(制表符、空格、换行符),并在输入流中搜索字母数字值。由于这是尾随空格,因此在按下 时,它与输入末尾的尾随换行符混为一谈,因此影响不大。scanf()ENTER

scanf()期望提供的输入与您提供给它的格式字符串完全匹配,但连续的空格字符被压缩为单个空格字符除外。如果要使用等效的字符串处理来解析大型数据字符串,这一点将变得非常重要。sscanf()

进一步测试这一点的一个很好的练习是这样的:

#include<stdio.h>

int main(void)
{
   int a=0,b=0,c=0;

   printf("Enter values for A, B, C, in the format: \"A B  -  C\"\n");
   scanf("%d %d  -  %d", &a, &b, &c);

   printf("Values: A:%d, B:%d, C:%d\n", a, b, c);
}

然后,在提供正确和错误格式的控制台输入(即:空格和连字符)后,检查并查看这些整数的值。下面是几个示例运行。第一个使用了不正确的输入,第二个使用了格式正确的输入。请注意,在第一种情况下,甚至没有设置,如果输入和格式字符串不匹配,则会提供意外行为。一般来说,你最好使用类似的东西从用户那里获取一串输入,然后使用各种搜索函数(即:strstr()、strch()、strcat、strcpy 等)来解析你的字符串,因为它比仅仅使用和假设用户不会犯错误要安全得多,无论是意外的还是故意的。Cscanf()fgets()scanf()

Enter values for A, B, C, in the format: "A B  -  C"
1 2 3
Values: A:1, B:2, C:0

Enter values for A, B, C, in the format: "A B  -  C"
1 2  -  3
Values: A:1, B:2, C:3

现在,考虑最后一次运行:你会看到将多个连续的空格字符压缩为一个字符,因此这些最终运行实际上成功了:scanf()

Enter values for A, B, C, in the format: "A B  -  C"
1 2 - 3
Values: A:1, B:2, C:3

Enter values for A, B, C, in the format: "A B  -  C"
1     2           -                     3
Values: A:1, B:2, C:3

评论

1赞 Chris Dodd 10/22/2013
-1:这些示例中格式字符串中的所有空格都是完全无关紧要的,可以在不更改结果的情况下删除,因此这并不能真正回答问题,即关于格式字符串中的尾随空格......
1赞 Cloud 10/24/2013
它确实总结了不同的空格字符是如何全部归为一个字符的,以及这个特定示例中的尾随空格如何无关紧要。它还描述了格式字符串如何实质上简化为预期空格和非空格的模式,以及如何根据输入何时偏离格式模式,为部分或所有目标变量分配值。我认为这是没有道理的。
1赞 Jonathan Leffler 9/15/2015
代码应记录并报告 的返回值。这将显示已设置了多少个值。格式字符串中的尾随空格与交互式输入不是“无关紧要的”。这意味着在输入完成之前,用户必须键入空格以外的字符(换行符是空格)。scanf()
0赞 Jonathan Leffler 9/15/2015
@ChrisDodd:格式中破折号前的空格之一很重要;其他人则不是。如果破折号前没有空格(例如),则输入 like 会失败,因为输入中的空格与格式中的破折号不匹配(但没问题)。你的主要观点是正确的;大多数空格在格式字符串中都是无关紧要的,但并非所有空格都是无关紧要的——正是这些空格的微妙之处困扰着 et al 的使用。格式字符串中的尾随空格尤其有害!"%d%d-%d"23 34 - 45"%d%d -%d"scanf()scanf()
4赞 Sergey L. 10/21/2013 #2

格式中的空格字符与任意数量的空格字符匹配,如 所述。因此,如果您有尾空格、换行符、制表符或任何其他空格字符,那么它也会在返回之前被消耗掉。scanfisspacescanf

评论

1赞 Jonathan Leffler 9/15/2015
这并不能明确关键点——在输入非空白区域之前,它不会返回。反过来,这意味着您必须猜测程序接下来要询问的内容,并在当前输入完成之前输入下一个值。(如果你不输入完整的下一个值,那么你会遇到更多问题;奇数一个字符(以及终端将字符发送到程序之前必须跟随的换行符)将被解释为下一个字段。交互式格式的尾随空间是可怕的!scanf()
6赞 haccks 10/22/2013 #3

格式字符串中的空格字符(空格、换行符、水平和垂直制表符)与输入中的任意数量的空格字符匹配。
在您的第一个案例中

  scanf("%d  ",&j);

当它遇到空格字符 (WSC) 时,它将吃掉用户输入的所有空格,包括按下时,并且它会期望进入非 WSC。在这种情况下,您的程序将通过按 + 终止。' '\nEnterCtrlZ

评论

1赞 Cloud 10/22/2013
它真的会在该命令作为顶层进程背景的 posix 系统上终止吗?
2赞 haccks 10/22/2013
@Dogbert;不确定,但对于 MS-WIN:Ctrl + D
39赞 Chris Dodd 10/22/2013 #4

scanf 格式的空格字符会导致它显式读取并忽略尽可能多的空格字符。因此,在读取一个数字后,它将继续读取字符,丢弃所有空格,直到它在输入上看到一个非空格字符。该非空格字符将保留为输入函数要读取的下一个字符。scanf("%d ", ...

使用您的代码:

printf("enter a value for j ");

scanf("%d  ",&j);

printf("j is %d \n", j);

它将打印第一行,然后等待您输入一个数字,然后继续等待该数字之后的内容。因此,如果您只是键入 ,它似乎会挂起 - 您需要输入另一行带有一些非空格字符才能继续。如果随后键入 ,这将成为 的值,因此您的屏幕将如下所示:5Enter6Enteri

enter a value for j 5
6
j is 5
enter a value for i i is 6

此外,由于大多数 scanf %-conversions 也会跳过前导空格(除 、 和 之外),因此 % 转换前的空格无关紧要(并且将以相同的方式执行操作)。因此,在大多数情况下,您应该避免在扫描转换中使用空格,除非您知道您特别需要它们来获得它们的特殊效果。%c%[%n"%d"" %d"