靜態數組的索引越界問題

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操作符創建)之後,我們就會避免索引越界問題和混用帶方括號的操作符問題,這樣可以極大減少麻煩。


發佈了36 篇原創文章 · 獲贊 15 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章