scanf("%[^ \n] s",a)vs得到(a)

nik*_*iko 9 c gets scanf

我被告知当用户输入字符串时不应使用scanf.相反,大多数专家和StackOverflow上的用户都可以使用gets().我从未在StackOverflow上问过为什么不应该使用scanf over gets for strings.这不是实际问题,但非常感谢对这个问题的回答.

现在来到实际的问题.我遇到过这种类型的代码 -

scanf("%[^\n]s",a); 
Run Code Online (Sandbox Code Playgroud)

这将读取一个字符串,直到用户输入一个新的行字符,同时将空格也视为字符串.

如果我使用有任何问题

scanf("%[^\n]s",a);
Run Code Online (Sandbox Code Playgroud)

而不是得到?

得到比scanf函数更优化,听起来,gets纯粹专门处理字符串.请让我知道这件事.

更新

这个链接帮助我更好地理解它.

sar*_*old 7

gets(3)是危险的,应该不惜一切代价避免.我不能想象一个使用其中gets(3)不是一个安全缺陷.

scanf(3)%s也是危险的-你必须使用'字段宽度’指定符,以表明您已经分配的缓冲区的大小.如果没有字段宽度,此例程就像以下一样危险gets(3):

char name[64];
scanf("%63s", name);
Run Code Online (Sandbox Code Playgroud)

GNU C库提供了a 修改,以%s该分配缓冲区为您服务.这种非便携式扩展可能不太正确使用:

   The GNU C library supports a nonstandard extension that
   causes the library to dynamically allocate a string of
   sufficient size for input strings for the %s and %a[range]
   conversion specifiers.  To make use of this feature, specify
   a as a length modifier (thus %as or %a[range]).  The caller
   must free(3) the returned string, as in the following
   example:

       char *p;
       int n;

       errno = 0;
       n = scanf("%a[a-z]", &p);
       if (n == 1) {
           printf("read: %s\n", p);
           free(p);
       } else if (errno != 0) {
           perror("scanf");
       } else {
           fprintf(stderr, "No matching characters\n"):
       }

   As shown in the above example, it is only necessary to call
   free(3) if the scanf() call successfully read a string.
Run Code Online (Sandbox Code Playgroud)

  • 您可以将长度修饰符与“%[”或“%s”一起使用。`%64[az]` 最多可读取 64 个小写字母字符,而 `%64s` 最多可读取 64 个非空白字符。 (2认同)
  • `char name [64]; scanf("%64s",name);`不应该是`scanf("%63s",name);`?留下了"NUL"字符的位置. (2认同)
  • 但是这个答案与这个问题有什么关系呢?问题是关于实现基于行的输入(而不是跳过空格)。`%s` 和 `a` 修饰符都与主题无关。 (2认同)

AnT*_*AnT 5

首先,不清楚s格式字符串中的作用。该%[^\n]部分是一个自给自足的格式说明符。%s正如您似乎相信的那样,它不是格式的修饰符。这意味着"%[^\n]s"格式字符串将被解释为scanf两个独立的格式说明符:%[^\n]后跟一个单独的s. 这将直接scanf读取所有内容,直到\n遇到(保持\n未读),然后要求下一个输入字符是s。这没有任何意义。任何输入都不会匹配这种自相矛盾的格式。

其次,明显的意思是scanf("%[^\n]", a)。这有点接近[不再可用] gets(或fgets),但并不相同。scanf要求每个格式说明符至少匹配一个输入字符。scanf如果它无法匹配请求的格式说明符的任何输入字符,则会失败并中止。这意味着scanf("%[^\n]",a)无法读取空输入行,即\n立即包含字符的行。如果您将这样的行输入到上面scanf,它将返回0以指示失败并保持a不变。这与典型的基于行的输入函数的工作方式非常不同。

(这是一种相当令人惊讶且看似不合逻辑的%[]格式。就我个人而言,我更希望%[]能够匹配空序列并生成空字符串,但这不是标准的scanf工作方式。)

如果您想以逐行方式读取输入,fgets这是您的最佳选择。