我有以下代码:
#include <stdio.h>
int main(void) {
char list[3][7] = { "One", "Two", "Three"} ;
char item[7]; // originally I had posted "char item[3];" by mistake
int i;
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
return 0;
}
我期待以下输出
0 One 1 Two
0 One 1 Two
然而,我得到了:
0 One 1 Two
0 1 Two
请注意第二次打印时丢失的文字“一”。
有人可以解释这里发生了什么吗?
谢谢!
答案 0 :(得分:1)
当你执行sprintf(item, "%-7s", list[i]);
时,实际上是将list[i]
中的字符串复制到char数组item
中。
所以list[2]
- &gt; &#34;三&#34;是5个字符加上n个终止符,但item
只有3个字符长 - 你溢出item
并写入其他内存,这很可能是list
的一部分。< / p>
将项目更改为char item[7]
,使其与list[3][7]
中第二维中声明的7的长度相匹配。当我这样做时,我得到了你的预期输出
(我用https://repl.it/languages/C来测试)
答案 1 :(得分:1)
将item
声明为:
char item[7];
代码公开未定义的行为,因为sprintf(item, "%-7s")
尝试将至少 8个字符写入item
。
documentation of sprintf()
解释(重点是我的):
格式字符串将结果写入字符串缓冲区。 如果要写入的字符串(加上终止空字符)超过缓冲区指向的数组的大小,则行为未定义。
-7
中的 "%-7s"
被解释为:
(可选)整数值或
*
,指定最小字段宽度。如果需要,结果将填充空格字符(默认情况下),右对齐时填充左侧,如果左对齐则填充右侧。在使用*
的情况下,宽度由类型int
的附加参数指定。如果参数的值为负,则会在指定-
标志和正字段宽度的情况下生成。 (注意:这是最小宽度:值永远不会被截断。)
为了避免未定义的行为,item
的大小必须至少为8
,但请记住,如果要格式化的字符串长于7
个字符,则不是截断后,结果会比8
个字符长,并且会再次溢出item
。
第一个循环中对sprintf(item, "%-7s", list[i]);
的调用在7个字符的缓冲区中写入8个字符。附加字符(\0
)偶然会覆盖list[0]
的第一个字符,将其更改为空字符串。 这只是一种随机行为,使用不同的编译器编译代码或不同的编译选项可能会产生不同的行为。