数组下标为负数出现的问题(关于数组下标越界的检查)

来源:互联网 发布:开源oa系统源码下载 编辑:程序博客网 时间:2024/05/12 00:56

同事有个程序出了点问题,先不谈这个,我先举个简单例子,如下:

///定义一个结构体

struct stTest
{
 int nA;
 int nB;
 int nArray[5];
};

///仔细的看下面的调用

 stTest Test;
 Test.nA = 101;
 Test.nB = 301;
 
 Test.nArray[-2] = 0;   ///注意数组下标为 -2

上面的代码在VC6下编译运行时都没有错误,注意在编译运行时都没有错误。

唯一的错误就是出现了意想不到结果。因为我们不想给数组下标为-2 的地方赋值。

上面的代码运行完后Test.nA的值变为 0 了。就是说给Test.nArray[-2] 赋值,其实是把值给了 Test.nA。

现在再做一个实验,定义两个全局变量,如下:

stTest Test2;
stTest Test;

然后在函数中进行如下调用:

void CDeletezsfedDlg::OnButton1()
{
 Test.nA = 101;
 Test.nB = 301;
 Test2.nB = 701;
 Test2.nA = 801;
 Test.nArray[-2] = 0;
 Test.nArray[6] = 0;   ///注意数组下标为 6,超出了实际的数组下标
}

在VC6下的实际运行结果为

Test2.nA = 0,也就是说Test.nArray[6]的赋值操作把Test2.nA的值改了。

 由此我不由想起上大学时对数组下标的争论,当时焦点是如果定义数组为

int a[10];

那么 a[10] 的访问范围是 0-9,还是 1-10,不要怪我们没有学好教材。当时做了个实验,0-9,1-10的范围都可以,哈,争论双方都无语了,访问1-10这个范围,现在想想这种做法是很危险的。还好,大家都知道数组是10个元素,还没有想超出10这个范围。

那今天上面举的例子超出了数组下标的范围,也没有出错,只是运行的结果与会与自己的预期有所不同而已。

总结下,C,C++不会对数组的下标进行严格的限制,这就需要用户自己严格把关了。

 现在对上面的现象进行分析:

 

先看内存分配

Test 的内存地址:0x004168a0

 Test.nA:0x004168a0

 Test.nB:0x004168a4

 Test.nArray:0x004168a8 

 

Test2 的内存地址:0x004168c0

 Test2.nA:0x004168c0

 Test2.nB:0x004168c4

 Test2.nArray:0x004168c8 

对于第一个例子:

 我们知道Test.nArray[0]的地址是0x004168a8,那么Test.nArray[-2]的地址是0x004168a8 - sizeof(int) * 2 = 0x004168a0,就是Test.nA的地址,所以如程序运行的那样把Test.nA的值改变了。

 

对于第二个例子:

 我们知道Test.nArray[0]的地址是0x004168a8,那么Test.nArray[6]的地址是0x004168a8 + sizeof(int) * 6 = 0x004168c0,就是Test2.nA的地址,所以如程序运行的那样把Test2.nA的值改变了。

当然我同事不会简单的犯上面的错误,他是以下面的方式进行数组元素赋值的(只是举例,不代表真实的程序)

Test.nArray[nIndex],而nIndex是运算的结果,因为没有检查,所以值为-2了就出现了上面的问题,我在排查这个问题的时候也很疑惑,直到用查看内存的方式发现把 Test.nA 的值改变了,然后跟进代码发现 nIndex 为 -2 了。

那么能不能防止这个问题呢,可以,如果我们在代码中加入下面的语句

if(nIndex >= 0 && nIndex < 6)

{

Test.nArray[nIndex] = 0;

}

就可以了。

但是每一次对数组访问都这么检查会有些麻烦,那就看你怎么选择了,在安全与便利之间都是要有所取舍的。

原创粉丝点击