未使用的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";