当我访问数组外部的项目时,我必须显示错误(不创建我自己的函数)。所以我只是认为有必要从数组中访问值来触发段错误,但这段代码根本不会崩溃:
int main(){
int tab[4];
printf("%d", tab[7]);
}
为什么我这样做时不会出错?
答案 0 :(得分:8)
当您调用undefined behavior时,任何事情都可能发生。您的程序可能会崩溃,可能会显示奇怪的结果,或者它似乎可能正常工作。
此外,进行看似无关的更改(例如添加未使用的局部变量或对printf
进行简单调用)可能会改变未定义行为的显示方式。
当我运行这个程序时,它完成并打印63.如果我将引用的索引从7更改为7000,我会得到段错误。
简而言之,仅仅因为程序 崩溃并不意味着它将。
答案 1 :(得分:2)
因为当您执行规范不允许的操作时的行为是"undefined"。而且因为C中没有必要的边界检查。你得到了#34;幸运"。
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。
答案 2 :(得分:1)
C中的数组只是一个指向内存块的指针,其起点为tab[0]
的任意位置。当然你已经设置了4
的界限但是如果你超过了它,你只需要访问超过那块内存的随机值。 (也就是说它可能打印出奇怪的数字)。