一道2016年nice的笔试题引发的思考

这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战


上一篇文章的问题代码,我认为有必要单独拿出来讲讲! 从代码角度,带你手把手调试(上) - 掘金 (juejin.cn)

回顾上文:

一个有问题的代码

int main()
{
	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (i = 0; i <=12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
	}
	return 0;
}
复制代码

执行结果:死循环打印hehe


为了发现问题:打印第几次打印

int main()
{
	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (i = 0; i <=12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
		printf("第%d次打印\n",i);
	}
	return 0;
}
复制代码

image.png i不能变为12


调试结果:

image.png

将第数组元素下标为12的值也改成0时,i也恢复为0,所以造成了死循环

**为什么呢?

猜想两个占用同一块空间

->验证

image.png



深入理解上述程序err原因

栈区先使用高地址,再使用低地址. 先定义变量i,所以i在高地址位置,然后再定义数组,二者相隔几个地址未知

arr和i中隔了几个元素是未知的,取决于编译器

image.png


变量和数组相隔距离

VC6.0中: arr和i是紧挨着的
VS2013-VS2019 arr和i中间有两个元素
gcc: arr和i之间放一个元素
复制代码

所以在VC6.0条件下,arr[10],写成i <= 10时就死循环了

如何解释:

i和arr是局部变量,放在栈区,栈区的使用习惯是先使用高地址,再使用低地址
画出栈区内存,上面低地址,下面高地址,先把高地址的空间使用了
i在下面创建,arr在上面创建,

又因为随着数组下标的增长,元素的地址又低到高变化
随着数组下标的越界访问,就可能覆盖循环变量i(二者占用同一块空间)
复制代码

问:当i和arr的创建反过来时:直接报错,不会死循环

因为内存布局发生变化

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i <=12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
		printf("第%d次打印\n",i);
	}
	return 0;
}
复制代码

执行结果:报错

注意

程序越界有一个报错的时间点,程序停下来时才报错,死循环了没时间报错

image.png


若改成release版本:

image.png

执行结果:打印13个hehe


在Debug情况下: i确实在数组后面存放, i的地址比数组地址大

image.png


而在Release版本:数组的地址更大 编译器进行了优化了,因为考虑到放后面可能出错

image.png


这也证明了Release版本确实可以优化


今天就先到这吧~感谢你能看到这里!希望对你有所帮助!欢迎老铁们点个关注订阅这个专题! 同时欢迎大佬们批评指正!

おすすめ

転載: juejin.im/post/7034383438601781279