【问题标题】:sscanf function usage in cc中的sscanf函数用法
【发布时间】:2012-09-13 03:55:33
【问题描述】:

我正在尝试使用sscanf 解析xxxxxx(xxxxx) 格式字符串,如下所示:

sscanf(command, "%s(%s)", part1, part2)

但似乎sscanf 不支持这种格式,因此part1 实际上包含整个字符串。

谁有这方面的经验,请分享...

谢谢

【问题讨论】:

    标签: c scanf


    【解决方案1】:

    将您的代码转换为程序:

    #include <stdio.h>
    
    int main(void)
    {
        char part1[32];
        char part2[32];
        char command[32] = "xxxxx(yyyy)";
        int n;
    
        if ((n = sscanf(command, "%s(%s)", part1, part2)) != 2)
            printf("Problem! n = %d\n", n);
        else
            printf("Part1 = <<%s>>; Part2 = <<%s>>\n", part1, part2);
        return 0;
    }
    

    运行时,它会产生“Problem! n = 1”。

    这是因为第一个 %s 转换说明符会跳过前导空白,然后扫描“非空白”字符直到下一个空白字符(或者,在这种情况下,是字符串的结尾)。

    您需要使用(否定的)字符类或 scansets 来获得您想要的结果:

    #include <stdio.h>
    
    int main(void)
    {
        char part1[32];
        char part2[32];
        char command[32] = "xxxxx(yyyy)";
        int n;
    
        if ((n = sscanf(command, "%31[^(](%31[^)])", part1, part2)) != 2)
            printf("Problem! n = %d\n", n);
        else
            printf("Part1 = <<%s>>; Part2 = <<%s>>\n", part1, part2);
        return 0;
    }
    

    这会产生:

    Part1 = <<xxxxx>>; Part2 = <<yyyy>>
    

    注意格式中的 31;它们可以防止溢出。


    我想知道 %31 是如何工作的。它是作为%s 工作并防止溢出还是只是防止溢出?

    对于给定的数据,这两行是等效的并且都足够安全:

        if ((n = sscanf(command, "%31[^(](%31[^)])", part1, part2)) != 2)
        if ((n = sscanf(command, "%[^(](%[^)])", part1, part2)) != 2)
    

    %[...] 表示法是一种转换规范; %31[...]也是如此。

    C 标准说:

    每个转换规范都由字符 % 引入。 在 % 之后,依次出现以下内容:

    • 一个可选的赋值抑制字符 *.
    • 大于零的可选十进制整数,指定最大字段宽度 (以字符为单位)。
    • 一个可选的长度修饰符,指定接收对象的大小。
    • 一个转换说明符字符,用于指定要应用的转换类型。

    31 是(可选)最大字段宽度的示例。 [...] 部分是一个scanset,它可能被视为s 转换说明符的一个特例。 %s 转换说明符大致等价于 %[^ \t\n]

    31 比字符串的长度小一;最后的 null 不计入该长度。由于part1part2 都是32 个char 的数组,所以%31[^(]%31[^)] 转换说明符可防止缓冲区溢出。如果第一个字符串在 ( 之前超过 31 个字符,则由于文字左括号不匹配,您将获得返回值 1。同样,第二个字符串将被限制为 31 个字符,但您无法轻易判断 ) 是否在正确的位置。

    【讨论】:

    • 非常感谢。但我想知道 %31 是如何工作的。它是作为 %s 工作并防止溢出还是只是防止溢出,sscanf 默认读取字符串。
    【解决方案2】:

    如果您确切知道“命令”的各个部分有多长,那么最简单的选择是:

    sscanf(command, "%6s(%5s)", part1, part2);
    

    这假定“part1”始终为 6 个字符,“part2”始终为 5 个字符(如您的代码示例中所示)。

    【讨论】:

      【解决方案3】:

      试试这个:

      #include <stdio.h>
      
      int main(void)
      {
        char str1[20];
        char str2[20];
        sscanf("Hello(World!)", "%[^(](%[^)])", str1, str2);
        printf("str1=\"%s\", str2=\"%s\"\n", str1, str2);
        return 0;
      }
      

      输出(ideone):

      str1="Hello", str2="World!"
      

      【讨论】:

      • 如果您扫描用户输入,您就是在利用漏洞。
      • @JimBalter 我知道头脑简单的代码的安全问题。
      猜你喜欢
      • 1970-01-01
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-19
      • 2011-10-22
      • 2014-12-22
      • 2017-06-03
      相关资源
      最近更新 更多