[英]Function sscanf must be assigned to variable otherwise strange behavior
[英]Strange behavior of sscanf
我发现了一些奇怪的东西。 这是代码示例:
...
char *start = strchr(value, '(');
if(start)
{
char buf[LEN];
memset(buf, 0, LEN);
int num = sscanf(start, "(%s)", buf);
if(num)
{
buf[strlen(buf) - 1] = '\0';
sprintf(value, "%s", buf);
}
...
例如,如果值是“(xxx)”,那么在执行此操作后,值将是“ xxx”。
但是,如果值是“([[34] xx {4,7} | 1234567890)””,则值将是“ [34] xx {4,7}”。
有人可以解释吗?
PS这是ARM平台。
int num = sscanf(start, "(%s)", buf);
在这里,当sscanf
在start
指向的缓冲区中遇到空白时,它会返回。 输入字符串中有一个空格:
"([34]xx{4,7}| 1234567890)"
^ space here
scanf
返回成功匹配和分配的输入项目数。 在这里,它将返回1
并且num
值为1
。 接下来,用if
块中的此语句覆盖buf
的最后一个字符。
buf[strlen(buf) - 1] = '\0';
这说明了程序的输出。 现在,关于您的代码的几件事:
你不需要做memset(buf, 0, LEN);
。 只需做char buf[LEN] = {0};
这将用空字节填充数组。
sscanf
不会检查缓冲区buf
的数组边界,在缓冲区buf
,您正在写入sscanf
从start
读取的字符串。 如果buf
的大小不够, sscanf
将尝试在缓冲区buf
之外的内存中进行写入。 由于非法的内存访问,这将导致不确定的行为,甚至导致程序崩溃。 您应该以sscanf
的格式字符串提供字段宽度,以防止缓冲区溢出。
#define STRINGIFY(s) #s // preprocessor command # stringifies the token s
#define XSTRINGIFY(s) STRINGIFY(s)
#define LEN 10 // max buffer length without the null byte
// inside a function
char buf[LEN + 1]; // +1 for the null byte
const char *format = "(" XSTRINGIFY(LEN) "%s)"; // "(%10s)"
int num = sscanf(start, format, buf);
在10
格式字符串"(%10s)"
意味着至多10
字符被存储在缓冲器指向buf
,然后一个空字节\\0
在端自动添加。 因此,在if
块中不需要以下内容:
buf[strlen(buf) - 1] = '\0'; // overwrites the last char before null byte in buf.
实际上,这样做会覆盖buf
的最后一个字符,因为strlen
不会计算空字节。
sscanf与%s一起使用,当遇到空白时,它将终止。 这就是您将输出显示为“ [34] xx {4,7}”而不是预期行为的原因
格式字符串由一系列指令组成,这些指令描述了如何处理输入字符的序列。 如果指令处理失败,则不会再读取任何输入,并且scanf()返回。 “失败”可以是以下之一:输入失败,表示输入字符不可用,或匹配失败,表示输入不合适(请参阅下文)。
在您的情况下, sscanf
匹配开始符(
,然后解析下一个令牌, %s
消耗数据直到第一个空格字符sscanf
然后不匹配a )
,这意味着解析停止。 已成功读取并分配了一个令牌,因此返回值为1
。
请注意,使用scanf
,您无法检测到在分配了最后一个令牌之后发生的匹配失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.