比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)

首先有如下代码:

#include

int main()

{

int i = 0;

int arr[] = {1,2,3,4,5,6,7,8,9,10};

for(i = 0;i<=12;i++)

{

printf("hehe\n");

arr [ i ] = 0;

}

system("pause");

return 0;

}

以下是此段代码的结果:

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第1张图片

由图可见,此段代码的结果为死循环打印hehe,这是因为什么原因呢?

我们可通过调试来发现问题,调试结果如下:

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第2张图片

由图片可知,当循环走完十个元素时,arr[]中的元素已经全部被赋值为0,那么当程序继续运行时,arr是否会越界访问第11个元素呢?我们接着往下看

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第3张图片

很显然,arr数组进行了越界访问,将第11个元素改为了0,我们接着往下看:

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第4张图片

当程序运行到最后一个值12时,再运行一次i++变成13,将不再满足循环,从而跳出循环结束打印。这是我们认为的结果,但事实果真如此吗?我们往下看

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第5张图片

我们可以惊奇的发现,当i=12运行过后,i居然被重新赋值为了0。这意味着i将重复以上程序的操作,无限循环直到系统崩溃。这也让我们找到了这份代码哪里出了问题。

到这只是发现了那一步出现了问题,并没有真正找到问题的起因以及解决方法。

我们可以接着往下探寻:

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第6张图片

既然arr[12]变为0时,i也同时变为0;那么,我们可以试着取一下i的地址与arr[12]的地址作比较,根据程序运行的结果可知,i与arr[12]的地址相同,这到底又是为什么呢?

这里我们就得提到数据在计算机中的存储:

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第7张图片

系统内存分为栈区,堆区和静态区,其中栈区是局部变量存放的地方,如图所示:

栈区的默认使用:

  1. 先使用高地址处的空间,

  1. 再使用低地址处的空间。

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第8张图片

而数组随着下标的增长地址由低到高变化,如图所示,从低地址依次向上为arr[1],arr[2]........arr[12],

由图我们可以惊奇的发现,i在栈区中存放的空间正好与arr[12]重叠,因此我们就找到了代码出现问题的原因。(这种情况是偶然出现的)

此代码在Debug与Release版本下的区别:

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第9张图片

Debug版本按照代码变量创建的顺序进行存储,因此i的内存空间在arr[]之上,在arr[]向上递增时,会越界出现错误。

比特鹏哥调试课之数据的储存与越界访问所带来的后果(包括Debug版本与Release版本)_第10张图片

Release版本下代码会自动进行优化,默认将i的存储空间放在arr[]存储空间之下,因此当arr[]递增时,并不会越界,代码也不会出现问题。

以上便是本文全部内容,有问题处欢迎各位大佬指正!

你可能感兴趣的:(c#)