未使用的char[]变量流入下一个变量
编码到 请看最后一行未使用的char[]变量流入下一个变量,c,C,编码到 请看最后一行 为什么会发生这种情况?信不信由你,“h”不是来自name。它只是一个随机垃圾,碰巧是一个“h” printf中的%s需要以null结尾的字符串。在全名的末尾没有\0,所以它只是不断读取额外的内存,而内存中恰好有一个h 更改您的全名声明即可: char full_name[] = { 'f', 'o', 'o', ' ', 'b', 'a', 'r', '\0' }; 编辑经过验证后,我承认——我说垃圾是随机的是错误的。AndreyT解释说堆栈可以“
为什么会发生这种情况?信不信由你,“h”不是来自
name
。它只是一个随机垃圾,碰巧是一个“h”
printf中的%s
需要以null结尾的字符串。在全名
的末尾没有\0
,所以它只是不断读取额外的内存,而内存中恰好有一个h
更改您的全名声明即可:
char full_name[] = {
'f', 'o', 'o',
' ', 'b', 'a', 'r', '\0'
};
编辑经过验证后,我承认——我说垃圾是随机的是错误的。AndreyT解释说堆栈可以“向后”加载,因此“h”来自name
,它在堆栈中的下一个内存位置。我仍然要强调的是,这是编译器依赖的,超过数组长度的访问会导致未定义的行为
char full_name[] = {'f', 'o', 'o', ' ', 'b', 'a', 'r' };
...
printf("full_name: %s", full_name);
“%s”
格式需要指向字符串的指针。字符
数组全名
不包含字符串,因为它不是以'\0'
空字符结尾的
printf
可能会继续在内存中打印字符,直到找到空字符为止,但底线是行为未定义
如果您使用字符串文字定义了全名
,它将正确地以null结尾:
char full_name[] = "foo bar";
显然,在您的平台上,局部变量在内存中的分配顺序是相反的
这意味着数组full\u name
的内存地址低于数组name
,即name
在内存中紧跟full\u name
。当您试图将数组full\u name
作为字符串输出时,printf
会跨越full\u name
的边界,因为您忘记了零终止它。它进入name
区域并从name
输出h
,最后从name
在零终止符处停止,可能是全名
的某个组合没有以空终止,它恰好位于堆栈上的name
旁边。不记得足够的规格,以确保如果这种情况总是发生,因此,这不是一个答案。(事实上,从答案来看,这根本不能保证会发生。)您的代码与输出不匹配。特别是,代码具有名称的大小(char[]):%ld\n
。您的输出没有匹配的行。@DennisMeng就是它!我错过了示例中的\0。您没有以null结尾的全名。您提供的输出与您提供的代码不匹配。有趣的断言。也许OP可以将“h”改为“x”,看看你对“name”的未更新声明是否是错误的(我敢打赌是错误的)。@RonBurk这会很有趣,但充其量只能提供有关编译器的信息。真正重要的是OP的字符串没有正确终止,导致printf
超出其数组的边界并产生未定义的行为。可能是这个特定的编译器将堆栈倒置,但通常name
的地址早于full\u name
。检验你的理论更好的方法是简单地打印两个变量的地址。我猜h
不是随机的。那h
实际上来自name
name
恰好位于内存中的full\u name
之后,因为在许多平台上,局部变量在内存中“按相反顺序”存储。在这一点上,我不得不向您和@RonBurk让步。我愿意接受1:256的巧合,即“h”是下一个,但1:65536的概率是“h\0”,这更可能说明您是对的。h不是随机的。字符名称[]=“hi”;产生全名:foo barhi name=“hi”和full\u name=“foo barhi”我自己显然没有投票,但真正的问题是full\u name
不是空终止的。在full\u name
的末尾之外,哪个特定的内存块碰巧被访问是偶然的。
char full_name[] = {'f', 'o', 'o', ' ', 'b', 'a', 'r' };
...
printf("full_name: %s", full_name);
char full_name[] = "foo bar";