我发现了一些奇怪的事情。以下是代码示例:
...
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}”。
谁能解释一下呢?
P.S。这是ARM平台。
答案 0 :(得分:2)
int num = sscanf(start, "(%s)", buf);
此处,sscanf
在遇到start
指向的缓冲区中的空格时返回。输入字符串中有一个空格:
"([34]xx{4,7}| 1234567890)"
^ space here
scanf
返回成功匹配和分配的输入项数。在此,它将返回1
,num
的值为1
。接下来,您将buf
块中的此语句覆盖if
中的最后一个字符。
buf[strlen(buf) - 1] = '\0';
这解释了你的程序的输出。现在,关于代码的一些事情:
您无需执行memset(buf, 0, LEN);
。只需执行char buf[LEN] = {0};
这将使用空字节填充数组。
sscanf
不会检查缓冲区buf
的数组范围,您正在编写sscanf
正在从start
读取的字符串。如果buf
的大小不够,sscanf
将尝试在缓冲区buf
之外的内存中写入。由于非法内存访问,这将导致未定义的行为甚至程序崩溃。您应该以{{1}}的格式字符串给出字段宽度,以防止缓冲区溢出。
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
指向的缓冲区中,然后是空字节{{1}最后会自动添加。因此,buf
块中不需要以下内容:
\0
事实上,这样做会覆盖if
中的最后一个字符,因为buf[strlen(buf) - 1] = '\0'; // overwrites the last char before null byte in buf.
不计算空字节。
答案 1 :(得分:1)
答案 2 :(得分:1)
格式字符串由一系列指令组成,这些指令描述了如何处理输入字符序列。如果指令处理失败,则不再读取其他输入,并返回scanf()。 “失败”可以是以下任何一种:输入失败,意味着输入字符不可用或匹配失败,这意味着输入不合适(见下文)。
在您的情况下,sscanf
匹配起始(
,然后解析下一个令牌%s
,该令牌消耗数据直到第一个空白字符。 sscanf
然后无法匹配)
,这意味着解析停止。成功读取并分配了一个令牌,因此返回值为1
。
请注意,使用scanf
时,无法检测在分配的最后一个令牌之后发生的匹配失败。