首先,数组越界访问是一个非常严重的问题,先看一个简单的代码:
#include<stdio.h>
int main()
{
int i;
int arr[10];
for(i=0;i<=10;i++)
{
arr[i] = 0;
printf("%d\n",i);
}
return 0;
}
运行结果如下:
我们可以看到,程序崩溃了。
从上面我们可以认识到,什么是数组越界呢?
我们通过数组的下标来得到数组内指定索引的元素。这称作对数组的访问。 如果一个数组定义为有n个元素,那么,对这n个元素(下标为0 到 n-一的元素)的访问都合法,如果对这n个元素之外的访问,就是非法的,称为“越界。 数组占用了一段连续的内存空间。然后,我们可以通过指定数组下标来访问这块内存里的不同位置。因此,当你的下标过大时,访问到的内存,就不再是这个数组“份内”的内存。你访问的,将是其它变量的内存了。
当博主修改代码为i<=12时,程序出现了死循环,如下:
为什么会出现这种情况,源自于栈这种数据类型“先进后出”特点,首先分析以下这个程序内存分配情况:程序先定义了一个int类型的变量i,接着定义了一个int类型的数组长度为10。在编译器中,内存以栈的数据结构来分配,利用栈“先进后出”的特点,先给i分配了一个4个字节的空间,再给长度为10 的数组分配了40个字节的空间按照栈的分配,数组arr的长度为10,第一个元素是arr[0],最后一个元素是arr[9],在程序循环过程中,10<=10成立,数组越界,这个“越”指的是当前合法位置的下一个,即arr[10]=0则指向了变量i的地址空间并对i赋值为0,此时i=0且i<=10以此类推,从而导致了程序的死循环。
原因是:因为数组越界,当i=10时,系统将i所对应的值赋为0,此时i=0且i<=10系统又会进入新一轮循环。以此类推,系统陷入死循环。
解决办法
i.编译器:Visual Studio 2012针对于上述问题会产生崩溃现象,具体实现过程如上图(右),VS12会在数组arr与变量i中间进行隔离,避免数组越界影响到i,同时在数组arr与变量i中间申请两个内存空间,分别放在两颗“炸弹”,数组一旦越界,触碰到炸弹,系统中断,提出警告。
ii.人力控制:牢记数组最大下标值=数组长度-1,代码仔细书写,避免越界问题产生。
int main()
{
int i;
int arr[10];
printf("%d,%d,%d\n",&i,&arr[8],&arr[9]);
return 0;
}
可以看到 i与arr[9]之间并不是我们所理解的4个字节,实际上它们相差12个字节(如上图),vs2012这两者之间多设置了两个4字节,以帮助用户检测程序,很大程度上避免了一些隐型的错误。