为什么 sscanf 会改变原始 char 数组的值?

Why does sscanf changing the value of original char array?

我不明白 sscanf 是如何工作的。

#include <stdio.h>
#include <string.h>

int main(void)
{

    char s[100] = "testtes te asdf newlinetest";

    char parm1[10];
    char parm2[4];
    char parm3[256];
    char parm4[10];

    printf("BEFORE: %s\n", s);
    sscanf(s, "%s %s %s %s", parm1, parm2, parm3, parm4);
    printf("AFTER: %s\n", s);

    return (0);
}

输出:

BEFORE: testtes te asdf newlinetest
AFTER: t

它似乎在打印最后一个字符,但是当 parm1 的大小为 90 时,它会打印正确的输出。

输出:

BEFORE: testtes te asdf newlinetest
AFTER: testtes te asdf newlinetest

parm4 中的 space 不足以容纳 "newlinetest"parm4 可以容纳 10 个字符,但是 "newlinetest" 是 11 个字符长,加上你需要一个额外的字符作为空字符,所以你需要 12 个字符来容纳它。在将前 10 个字符写入 parm4 后,它会继续,将 t[=16=] 写入 parm4 之后的内存,在本例中显然是 s.所以 s 最终持有 "t".

请注意,这是未定义的行为,您不能指望它会以这种方式表现。

param4 不够大,无法容纳字符串“newlinetest”。结果,当 sscanf 写入它时,它写入了数组的末尾。这会触发 undefined behavior.

在这个特殊的案例中,s恰好出现在内存中param4之后,所以[=12=的前几个字节] 被覆盖。然而,这只是该程序的一种行为方式。它本可以正常工作。

通过增大 param4,可以防止写入超过数组末尾。

存在内存覆盖,因为以下数组仅使用 10 个字符声明,如

char parm4[10];

并且您正在尝试向其写入包含 12 个字符的字符串 "newlinetest",其中包括终止零字符 '[=15=]'.

至少用 12 个字符声明数组

char parm4[12];

你会得到预期的结果。

除了答案中已经说过的,当你使用sscanf()解析字符串时,最好使用宽度修饰符:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char s[100] = "testtes te asdf newlinetest";

    char parm1[10];
    char parm2[4];
    char parm3[256];
    char parm4[12]; // 12 since your last word contains 11 characters (+1 for [=10=])

    printf("BEFORE: %s\n", s);
    sscanf(s, "%9s %3s %255s %11s", parm1, parm2, parm3, parm4);
    printf("AFTER: %s\n", s);
}

您的输出应如下所示:

BEFORE: testtes te asdf newlinetest
AFTER: testtes te asdf newlinetest