目录
声明
原题
题目详细解析
运行结果:
题目解析:
结论1:
注意点1:
注意点2:
结论2:
注意点3:
注意点4:
注意点5:
声明
今天的题,并非是完全出自于nice的笔试原题,今天的这道题出自于《C陷阱和缺陷》,只是两道题有异曲同工之妙!
原题
#include <stdio.h> int main() { int i = 0; int arr[10] = { 0 }; for (i = 0; i <= 12; i++) { arr[i] = 0; printf("hehe\n"); } return 0; }
问题:这段代码在vs2019上会出现什么现象?这种现象是由什么原因造成的?我们应该如何避免像这样的问题?
题目详细解析
运行结果:
出现了死循环,即在屏幕上不停的打印"hehe"。
题目解析:
(1)i和arr是局部变量,放在栈区上
(2)栈区上的使用习惯:先使用高地址处的空间,再使用低地址处的空间
(3)数组随着下标的增长,地址是由低到高变化的
由这三点可以画出这段程序的内存图来,当然,这还要区分具体的编译器!
结论1:
arr[12]与变量i占用的是同一块空间,即地址值一样
如果arr和i之间的空间合适的话,就有可能使用的arr数组向后越界访问到了i,造成循环变量i的改变,最终死循环。
注意点1:
这个代码是严格依赖环境的,例如vc 6.0 中i和arr是连续的,在gcc编译器中,i和arr之间有一个空间。
注意点2:
虽然此程序越界访问了,但是由于程序进入了死循环,所以不会报错,但是一旦把i<=12改成了i<=11,程序就会在i=11的地方会停止下来,此时已经构成了越界访问,程序自然会报错。如下图所示:
结论2:
死循环会掩盖程序中的某些错误,比如数组越界访问。
注意点3:
当把int i = 0;与int arr[10] = {0};交换之后,程序将不会出现死循环,但是程序的越界访问报错是少不了的。
注意点4:
此时也应该注意一下debug与release版本的区别:
很明显,在debug版本下,i的地址值比arr[9]的要大,而在release版本下,i的地址要比arr[9]的地址值要小,在release版本下进行了某些优化,即杜绝了我们上述出现的死循环的情况,在这种情况下,即使数组越界,也不会影响到i的值。
注意点5:
这种优化是无差别的,即无论你的代码是否越界,都会进行这样的优化。