多維數組的索引越界問題

1、我們大都知道可以使用vector或array模板作爲線性數組的實現,那麼對於需要二維矩陣、三維數組(或者N維數組)時應該怎麼解決。

由於N維數組的基本情況中的所有問題都可以用一個二維矩陣舉例說明,因此以下的討論僅限於此,並簡單的稱爲矩陣。

如果矩陣的大小在編譯時是已知的,可以很方便的把它實現爲數組的數組,這個很簡單。這裏,我們主要把注意力集中在當矩陣的大小是在運行時計算產生,對於這種複雜的情況,我們可以很方便的使用vector或的vector來實現。事實上,如果不同的行必須必須具有不同的長度,這也是唯一可行的方法。但是,在大多時候,所有的行應該具有相同的長度,此時使用vector的vector是一種效率不高的方法:它需要多次分配內存,這是相對較慢的操作。由於我們使用C++的一個重要原因是追求高效,因此我們嘗試一種不同的方法,即只通過一次內存分配來創建一個長方形的矩陣。

示例代碼:

//二維長方形矩陣
template <typename T>
class matrix
{
public:
	typedef unsigned size_type;

	matrix(size_type num_rows, size_type num_cols)
		:rows_(num_rows),cols_(num_cols),data_(num_rows*num_cols)
	{
		SCPP_TEST_ASSERT(num_rows > 0,
			"Number of rows in a matrix must be positive");
		SCPP_TEST_ASSERT(num_cols > 0,
			"Number of columns in a matrix must be positive");
	}

	matrix(size_type num_rows, size_type num_cols, const T& init_value)
		:rows_(num_rows),cols_(num_cols),data_(num_rows*num_cols,init_value)
	{
		SCPP_TEST_ASSERT(num_rows > 0,
			"Number of rows in a matrix must be positive");
		SCPP_TEST_ASSERT(num_cols > 0,
			"Number of columns in a matrix must be positive");
	}

	size_type num_rows() const { return rows_; }
	size_type num_cols() const { return cols_; }

	//訪問方法:返回由行和列所指定的元素
	T& operator() (size_type row, size_type col)
	{
		return data_[index(row,col)];
	}

	const T& operator() (size_type row, size_type col) const
	{
		return data_[index(row,col)];
	}

private:
	size_type rows, cols;
	std::vector<T> data_;

	size_type insex(size_type row, size_type col) const
	{
		SCPP_TEST_ASSERT(row < rows_, "Row " <<row<<" must be less than "<<rows_);
		SCPP_TEST_ASSERT(col < cols_, "Column  " <<col<<" must be less than "<<cols_);
		return cols_* row + col;
	}
};

首先,這個類中有2個構造函數。第一個構造函數允許我們用指定的行數和列數創建一個矩陣。第二個構造函數具有一個額外的init_value參數,允許把每個元素初始化爲一個指定的值(例如,把一個matrix<double>的每個元素設置爲0.0)。注意,對元素的訪問時通過()操作符進行的。這是因爲C++的[]操作符只接受1個參數,不能接受2個參數或更多的參數。因此,爲了訪問多維數組,我們或者使用多個[](例如my_matrix[i][j]),或者使用1個()操作符(例如my_matrix(i,j))。

如果我們讓[]操作符返回指向第i行第0個元素的T*類型的指針,就可以實現第一種方法。但是,這樣就無法診斷列索引越界的問題,違背了在運行時捕捉缺陷的初衷。當然,我們可以創建一些模板類,包括一個指向一個列的智能引用,並使用第一個操作符([i])返回它的一個實例,並在第二個操作符([j])中使用邊界檢查。在某種程度上,這是因人的習慣。我們看不到僅僅爲了保留my_matrix[i][j]的語法而採用這種複雜設計的價值,顯然具有多個參數的()操作符看上去更爲直觀。

對索引越界的檢查是在index(row,col)函數中執行的,這兩個參數分別表示行數和列數。如果出現了運行時錯誤,就會導致一個錯誤處理函數被調用。

最後,在示例代碼最後,提供一個matrix<T>模板的<<操作符,是爲了輸出矩陣:

cout<<"my matrix = \n"<<my_matrix<<endl;

但是,前提是這個矩陣不能太大,並且類型T定義了<<操作符。


總結:避免“索引越界”的規則:

  • 不要使用靜態或動態分配的數組,可以改用array或者vector模板
  • 不要使用帶方括號的new和delete操作符,讓vector模板爲多個元素分配內存
  • 使用scpp::vector代替std::vector,使用scpp::array代替靜態數組,並打開安全檢查
  • 對於多維數組,使用scpp::matrix,並通過()操作符訪問元素,已提供索引越界檢查。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章