是否允许NULL
指针作为字符串来存储调用sscanf
的结果?我在任何文档中都没有找到任何相关信息,但似乎工作正常。与scanf
相同。
示例:
int main(int arc, char* argv[])
{
char* s = NULL;
sscanf("Privjet mir!", "%s", s);
printf("s: %s\n", s);
return 0;
}
输出:s: (null)
答案 0 :(得分:7)
没有
匹配一系列非白色空间 字符;下一个指针必须是a 指向字符数组的指针 足够长的时间来保存输入序列 和终止空字符 ('\ 0'),自动添加。 输入字符串在空格处停止 或者在最大场宽, 以先到者为准。
答案 1 :(得分:4)
正如其他答案中所提到的,NULL
无法传递给sscanf
作为附加参数。
http://www.cplusplus.com/reference/cstdio/sscanf说出了其他论点:
根据格式字符串,函数可能需要一系列附加参数,每个参数都包含一个指向已分配存储的指针,其中提取字符的解释以适当的类型存储。
For the %s
specifier these extracted characters are:
任意数量的非空白字符,在找到的第一个空白字符处停止。在存储序列的末尾会自动添加一个终止空字符。
因此,当存储“非空白字符”和“终止空字符”时,将存在段错误。这正是Visual Studio将产生的(您可以在http://webcompiler.cloudapp.net/测试它失败):
现在,对于非Visual Studio编译器,libc的%s
说明符的提取代码:https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376具有主要注释:/* We might have to handle the allocation ourselves */
这是因为:
GNU C库通过
a
字符支持动态分配转换说明符(作为非标准扩展名)。这个功能似乎至少可以追溯到glibc 2.0 从版本2.7开始,glibc还提供m
修饰符,其作用与a
修饰符相同。
[Source]
因为libc提取到内部构造到sscanf
的缓冲区,然后在分配之前检查缓冲区参数没有设置标志,它永远不会将字符写入NULL
缓冲区参数。
我不能强调这是非标准的,并且即使在次要库更新之间也不能保证。更好的方法是使用*
子说明符:
表示要从流中读取数据但忽略该数据(即它不存储在参数指向的位置)。
[Source]
这可以像这样完成:
s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s);
显然,三元组的真正分支是无操作,但我已将其包含在内,期望其他数据可以从字符串中读取。
答案 2 :(得分:1)
该联机帮助页说,在使用%s
时,参数必须是具有足够空间的字符串和\0
。所以我的猜测是你的情况下的行为是未定义的。它可能会起作用,它也可能会崩溃或损坏内存并在以后引起问题。
答案 3 :(得分:1)
不,这是不允许的。 sscanf%s期望char *指向足够大的缓冲区,printf%s需要一个nul char *缓冲区。任何其他因素都会导致未定义的行为。 (这意味着某些实现可能以某种方式检测和处理空指针,其他实现可能不会)
答案 4 :(得分:1)
我没有在标准中明确找到有关NULL
和*printf
/ *scanf
的内容。
我认为这是未定义的行为 1 ,因为它计算为传递与格式说明符不一致的参数(§7.19.6.1¶13,§7.19.6.2¶13): %s
表示您要将指针传递给字符数组的第一个元素(对于*scanf
的获取字符串足够大,包含NUL
- 终止的字符串{ {1}}) - 并且传递*printf
不符合此要求。
<小时/> 1.在这种情况下,UB显示为“只是忽略采集”和“打印(空)”,在其他平台上,它可能导致飞机坠落在天空或平常nasal demons。
答案 5 :(得分:-1)
将内存分配给s。将s分配给字符数组。然后运行该程序。 以下将有效。
int main(int arc, char* argv[])
{
char s[100];
sscanf("Privjet mir!", "%[^\t]s", s);
printf("s: %s\n", s);
return 0;
}