sscanf在%[^-] s匹配后缺少字符串

时间:2019-02-09 22:57:45

标签: c scanf

我有一个使用sscanf的简单程序。 我遇到的问题是,匹配%[^-]s后,sscanf似乎才停止匹配。

这是简单的代码,可以理解我的意思。 %s之后的%[^-]s %s匹配将被完全忽略。

注意:我需要%[^-]s,因为我需要我的程序来匹配两个可能的字符串。

注2:我知道代码是完全不安全的,等等。这只是一个例子!

#include <stdio.h>

int main(void) {
    int matches;
    int num1, num2, num3, num4;
    char *s1[10];
    char *s2[10];
    char *s3[40];
    char *s4[50];
    char *s5[50];
    char *s6[50];
    char *s7[50];

    char fileTest[] = "29 0 8:4 / / rw,relatime shared:1 - ext4 /dev/sda4 rw,errors=remount-ro";
    // char fileTest[] = "160 48 179:56 /inte /var/oil/gaol/org.something.org/media/internal ro,nosuid,relatime - ext4 /dev/mmccc rw,data=ordered";

    matches = sscanf(fileTest, "%d %d %d:%d %s %s %[^-]s %s",
                     &num1, &num2, &num3, &num4, s1, s2, s3, s4);

    printf("matches: %d\n", matches);
    printf("num1: %d\n", num1);
    printf("num2: %d\n", num2);
    printf("num3: %d\n", num3);
    printf("num4: %d\n", num4);
    printf("s1: %s\n", s1);
    printf("s2: %s\n", s2);
    printf("s3: %s\n", s3);
    printf("s4: %s\n", s4);

    return 0;
}

3 个答案:

答案 0 :(得分:7)

请注意,s扫描集之后的%[…]是文字s,而不是扫描集的一部分。在上下文中,%[^-]s将永远与s不匹配,因此以下任何转换都会失败。 %[^-]部分吞噬了所有不是破折号-的东西(而s不是-,因此它变得残缺不全,以及空格和其他所有内容),则s不匹配(因为转换在-或字符串结尾处停止),所以扫描在那里失败,并且最后一个%s也不匹配。

请参阅sscanf()的POSIX规范。阅读。重新阅读。重新阅读。重新重新阅读它。今天!和明天一样。您可以在一周的其余时间每天缩减为两次,然后每天缩减为另一周,然后每月缩减为一个月,每月一次,然后在一年中的剩余时间缩减为每月一次,此后至少每年一次。 scanf()函数家族可能是最难使用的标准C函数。

您的代码还有其他主要问题。特别是,char *s1[10];应该是char s1[10];,对于其他数组也应类似。或者,您需要进行一些主要的练习来分配要指向的数组的空间,等等。而且,您可能已经知道,%s(和%[^-])转换并不限制输入。使用%9s%49[^-]等来设置适当的尺寸。另请参见How to prevent scanf() causing a buffer overflow in C?

答案 1 :(得分:5)

格式说明符%[^-]匹配所有内容,直到遇到-为止;因此,在匹配此字符串之后,缓冲区中要检查格式字符串的下一个字符是-(如果有)。但是,如果让此模式遵循s,即%[^-]s,则将不再匹配,因为-从不匹配格式字符串中所需的s。 / p>

答案 2 :(得分:2)

您的代码中存在多个问题:

  • 字符类的sscanf格式为%[chars]%[^chars],在s之后没有尾随的]。在您的示例中,sscanf()将尝试在第三个字符串后匹配s并失败,从而阻止后续%s的转换。

  • 目标数组s1s4应该是char数组,而不是char *的数组。

  • 格式应指定要存储到目标数组中的最大字符数。您确实提到了代码不安全,因此您可能已经意识到了这一点,但是最好养成这样做的习惯。

  • 因为%[^-]停在-或输入字符串的末尾,所以%s解析的最后一个字符串将是-或{{1} }计数将反映缺少match分隔符。如果需要其余输入,则应使用-

这是更正的版本:

%[^\n]

输出:

#include <stdio.h>

int main(void) {
    int matches;
    int num1, num2, num3, num4;
    char s1[10], s2[10], s3[40], s4[50];

    char fileTest[] = "29 0 8:4 / / rw,relatime shared:1 - ext4 /dev/sda4 rw,errors=remount-ro";
    // char fileTest[] = "160 48 179:56 /inte /var/oil/gaol/org.something.org/media/internal ro,nosuid,relatime - ext4 /dev/mmccc rw,data=ordered";

    matches = sscanf(fileTest, "%d %d %d:%d %9s %9s %39[^-] - %49[^\n]",
                     &num1, &num2, &num3, &num4, s1, s2, s3, s4);

    printf("matches: %d\n", matches);
    printf("num1: %d\n", num1);
    printf("num2: %d\n", num2);
    printf("num3: %d\n", num3);
    printf("num4: %d\n", num4);
    printf("s1: %s\n", s1);
    printf("s2: %s\n", s2);
    printf("s3: %s\n", s3);
    printf("s4: %s\n", s4);

    return 0;
}