9

有人告诉我,用户输入字符串时不应使用 scanf。相反,大多数专家以及 StackOverflow 上的用户都使用 gets()。我从来没有在 StackOverflow 上问过它为什么不应该使用 scanf 来获取字符串。这不是实际问题,但非常感谢您回答这个问题。

现在进入实际问题。我遇到了这种类型的代码-

scanf("%[^\n]s",a); 

这会读取一个字符串,直到用户输入一个换行符,将空格也视为字符串。

如果我使用有什么问题吗

scanf("%[^\n]s",a);

而不是得到?

Is 听起来比 scanf 函数更优化,gets 纯粹专用于处理字符串。请让我知道这件事。

更新

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

4

2 回答 2

6

gets(3)是危险的,应该不惜一切代价避免。无法想象没有安全漏洞的gets(3)用途。

scanf(3)'s%s也是危险的——你必须使用“字段宽度”说明符来指示你分配的缓冲区的大小。如果没有字段宽度,此例程与以下一样危险gets(3)

char name[64];
scanf("%63s", name);

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.
于 2011-11-18T04:39:26.287 回答
4

首先,尚不清楚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这是您的最佳选择。

于 2016-11-10T20:59:46.453 回答