因为当你做规范不允许的事情时的行为是"undefined"。而且因为在 C 中不需要边界检查。你很“幸运”。
int tab[4]; 表示为堆栈上的 4 个整数分配内存。 tab 只是内存地址的数字。它不知道它指向什么或分配了多少空间。
printf("%d", tab[7]); 表示打印出tab 的第 8 个元素。所以编译器会...
-
tab 设置为 1000(例如)表示内存地址 1000。
-
tab 表示int 的列表,因此每个元素将是sizeof(int),可能是4 或8 个字节。假设是 8。
- 因此
tab[7] 表示从内存位置 (7 * 8) + 1000 = 1056 开始读取,再读取 8 个字节。所以它的读数是 1056 到 1063。
就是这样。程序本身没有边界检查。硬件或操作系统可能会进行边界检查以防止一个进程读取任意内存,请查看protected memory,但 C 不需要任何内容。
所以tab[7] 忠实地复制了 1056 到 1063 中的任何垃圾。
你可以写一个小程序来看看这个。
int main(){
int tab[4];
printf("sizeof(int): %zu\n", sizeof(int));
printf("tab: %d\n", tab);
printf("&tab[7]: %d\n", &tab[7]);
/* Note: tab must be cast to an integer else C will do pointer
math on it. `7 + tab` gives the same result. */
printf("(7 * sizeof(int)) + (int)tab: %d\n", (7 * sizeof(int)) + (int)tab);
printf("7 + tab: %d\n", 7 + tab);
}
确切的结果会有所不同,但您会看到 &tab[7] 只是对 tab 进行的一些数学运算,以确定要检查的内存地址。
$ ./test
sizeof(int): 4
tab: 1595446448
&tab[7]: 1595446476
(7 * sizeof(int)) + (int)tab: 1595446476
7 + tab: 1595446476
1595446476 - 1595446448 是 28。7 * 4 是 28。