NULL arg允许sscanf?

时间:2011-03-02 14:11:46

标签: c scanf

是否允许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)

6 个答案:

答案 0 :(得分:7)

没有

  

匹配一系列非白色空间   字符;下一个指针必须是a   指向字符数组的指针   足够长的时间来保存输入序列   和终止空字符   ('\ 0'),自动添加。   输入字符串在空格处停止   或者在最大场宽,   以先到者为准。

http://linux.die.net/man/3/sscanf

答案 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/测试它失败):

enter image description here

现在,对于非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;
}