为什么 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
我不明白 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