静态数组的索引越界问题

来源:互联网 发布:手机视频恢复软件 编辑:程序博客网 时间:2024/05/21 15:46

1、静态数组

处理静态数组:

#define N 10  //数组的长度N在编译时已知  T  static_array[N];
这里,数组的长度在编译时是已知的并且不会改变。当然,为了使用具有边界检查的安全数组,也可以vector模板,并在一个构造函数中指定它的长度:

scpp::vector vect(N);
它的效果与静态数组完全相同,但问题在于效率。静态数组是在堆栈上分配内存,而vector模板是在构造函数中用new操作符分配内存的,速度相对慢一些。如果运行时效率至关重要,最好使用array模板,即
namespace scpp{//固定长度的数组template <typename T, unsigned N>class array{public:typedef unsigned size_type;//最常用的构造函数array() {};explicit array(const T& initial_value){for(size_type i=0; i<size(); ++i)data_[i] = initial_value;}//注意:这里并没有提供拷贝构造函数和赋值操作符//依赖的是编译器生成的这些方法的默认版本T& operator[] (size_type index){SCPP_TEST_ASSERT(index < N,"Index "<<index<<" must be less than "<<N);return data_[index];}const T& operator [] (size_type index) const{SCPP_TEST_ASSERT(index < N,"Index "<<index<<" must be less than "<<N);return data_[index];}//模拟迭代器的访问方法T* begin() {return &data_[0];}const T* begin()const{return &data_[N];}private:T data_[N];};}//namespace SCPP
这个数组的行为与C的静态数组完全一样。但是,在编译时激活了表示安全检查的SCPP_TEST_ASSERT宏时,它会提供索引边界检查。它提供了用于模拟迭代器的begin()和end()的方法,因此这种数组在有些场合可以代替vector模板(例如,用于对数的排序)、例如下面的程序使用了STL的sort算法对这个数组进行排序:

#include<algorithm> scpp::array<int, 5> a(0); a[0] = 7; a[1] = 2; a[2] = 3; a[3] = 9; a[4] = 0; cout<<"Array before sort: "<<a<<endl; sort(a.begin(), a.end()); cout<<"Array after sort: "<<a<<endl; endl;
程序运行后产生的结果输出为:

Array before sort:7 2 3 9 0

Array after sort: 0 2 3 7 9

作为一个附加的优点,我们还可以使用<<操作符,它允许我们像前面那个例子一样把一个数组输出到流中,只要这个数组不至于太大,并且模板类型T定义了<<操作符。当然,这种固定长度的数组在使用时必须限制在数组长度N不会太大的情况下。否则,就会把大量的堆栈内存(一种有限的资源)消耗在这个数组上。

因此,建议不要使用静态或者动态分配数组,而是使用vector或array模板。这种做法可以解决当我们使用了带了方括号的new操作符时,在使用delete操作符时也要带方括号。如果错用了这两个操作符带方括号(new带方括号,而delete没带方括号或者反过来),就会破坏内存堆,一般会导致不良后果。决定不使用动态分配的数组(通过带方括号的new操作符创建)之后,我们就会避免索引越界问题和混用带方括号的操作符问题,这样可以极大减少麻烦。


0 0
原创粉丝点击