繁体   English   中英

sscanf的奇怪行为

[英]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);

在这里,当sscanfstart指向的缓冲区中遇到空白时,它会返回。 输入字符串中有一个空格:

"([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 ,您正在写入sscanfstart读取的字符串。 如果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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM