我被告知当用户输入字符串时不应使用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纯粹专门处理字符串.请让我知道这件事.
更新
这个链接帮助我更好地理解它.
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格式字符串中的作用。该%[^\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这是您的最佳选择。