在C++中,STL的map与set的元素通过键(key)来访问元素的值,而数组作为一种顺序结构,通过其元素的位置来访问其元素的值。
在C++中,数组名相当于一个指针常量,下标内的数字相当于是指针的偏移位置,如arr[i],相当于*(arr+i)。
在C++中,如果定义的数组:int arr[n],其指针arr偏移的范围应该是n>=0&&n<10,但偏移器并不检查n的取值范围,这就是数组的不安全的原因,如下例:
#include <iostream> using namespace std; const int SIZE = 10; int main() { int before = 111; int arr[SIZE]; for(int i=0; i<10; ++i) arr[i]=i; int after = 999; cout << "arr[-2] 的值为 : " << ++arr[-2] <<endl; cout << "arr[2] 的值为 : " << arr[2] <<endl; cout << "arr[9] 的值为 : " << arr[9]<<endl; cout << "arr[10] 的值为 : " << ++arr[10]<<endl; cout<<before<<" "<<after<<endl; system("pause"); return 0; } /* arr[-2] 的值为 : 1000 arr[2] 的值为 : 2 arr[9] 的值为 : 9 arr[10] 的值为 : 112 112 1000 */
从上面实例的代码运行后可见,编译器并没有检查数组下标的边界,当用指针arr偏移出其边界时,修改的是临近区域的值。
C风格的字符串也因为同样的原因,存在不安全的因素,为此,在C++中也定义了string类,对C风格的字符串进行封装,同样的,STL也封装了动态数组,建立了vector类。关于vector类的实现代码,可见:
下面的实例就是封装一个数组类,对下标的边界进行检查:
#include <iostream> using namespace std; const int SIZE = 10; class Arrs { private: int arr[SIZE]; public: Arrs() { register int i; for(i = 0; i < SIZE; i++) { arr[i] = i; } } int& operator[](int i) { if( i >= SIZE ) { cout << "索引超过最大值" <<endl; // 返回第一个元素 return arr[0]; } if( i < 0 ) { cout << "索引小于0" <<endl; // 返回第一个元素 return arr[0]; } return arr[i]; } }; int main() { int before = 111; Arrs arr; int after = 999; cout << "arr[-1] 的值为 : " << arr[-1] <<endl; cout << "arr[2] 的值为 : " << arr[2] <<endl; cout << "arr[9] 的值为 : " << arr[9]<<endl; cout << "arr[10] 的值为 : " << arr[10]<<endl; cout<<before<<" "<<after<<endl; system("pause"); return 0; } /* 索引小于0 arr[-1] 的值为 : 0 arr[2] 的值为 : 2 arr[9] 的值为 : 9 索引超过最大值 arr[10] 的值为 : 0 111 999 */
从上面实例的代码运行后可见,当偏移出其类的成员数组的边界时,因做了边界检查,并不会修改临近变量的值,一定程度上实现了安全性。
-End-