我在一道测试题中对这段C代码感到困惑:
我看到的问题问我这段代码会打印什么,显而易见的答案是
我想也许有时候它会打印一些垃圾值,而有时候会按预期工作,但是尝试了几次后,我发现它总是按预期工作。
之后,我决定越界访问并检查数组后面的字节,特别是
我不知道为什么会发生这种情况。起初,我以为可能是一些字大小的内存分配导致后面的字节为零,但是看到它们有时候也可能是非零值,让我感到困惑。
之后,我尝试简化代码:
这段代码打印了
为什么会发生这种情况?如何发生的?
我在一台64位机器上使用gcc 13作为编译器,如果有帮助的话。
附注:我有点期望能够以内存中分配的顺序来解释,而不仅仅称之为未定义行为。据我所知,局部变量在内存位置上是相邻的。也许在
#include <stdio.h>
union Data {
char var1;
char var2;
char varArr[10];
};
int main() {
union Data data;
data.var1 = 'a';
data.var2 = 'b';
data.varArr[0] = 'c';
char ctr[3];
ctr[0] = data.var1;
ctr[1] = data.var2;
ctr[2] = data.varArr[0];
printf("Result: %s\n", ctr);
return 0;
}
我看到的问题问我这段代码会打印什么,显而易见的答案是
ccc
,但是数组的长度是3,所有的元素都是c
,这让我感到困惑(末尾没有\0
)。我想也许有时候它会打印一些垃圾值,而有时候会按预期工作,但是尝试了几次后,我发现它总是按预期工作。
之后,我决定越界访问并检查数组后面的字节,特别是
ctr[3]
、ctr[4]
和ctr[5]
,以进一步了解。我注意到这些字节通常是\0
,但并不总是。当它们不是\0
时,它们通常会取一些小的垃圾值,比如0x01
或0x04
(在这种情况下,它们真的是垃圾值吗?我不知道),但是在这些情况下,也会打印出ccc
。我不知道为什么会发生这种情况。起初,我以为可能是一些字大小的内存分配导致后面的字节为零,但是看到它们有时候也可能是非零值,让我感到困惑。
之后,我尝试简化代码:
#include <stdio.h>
int main() {
char ctr[3];
ctr[0] = 'c';
ctr[1] = 'c';
ctr[2] = 'c';
printf("Result: %s\n", ctr);
return 0;
}
这段代码打印了
cccX
(X是一些看起来在不同运行中大小和内容都在变化的垃圾值)。所以,这两段代码在内存上有一些差异,这是由第一段代码中的局部data
变量引起的,但我无法弄清楚原因。为什么会发生这种情况?如何发生的?
我在一台64位机器上使用gcc 13作为编译器,如果有帮助的话。
附注:我有点期望能够以内存中分配的顺序来解释,而不仅仅称之为未定义行为。据我所知,局部变量在内存位置上是相邻的。也许在
data
的位置写入的内容以某种方式影响了打印ctr
的工作方式。但如果未定义行为是我能得到的最终答案,我也想知道为什么。感谢对未定义行为的解释 :)