此處的數組非順序容器array
初始化,
使用下標訪問數組時,下標定義為size_t類型。
beg 和 end 函數(注意和 順序容器中的 beg end成員的區別)
int a[10];
int *beg = beg(a);
int *end = end(a); // 返回末尾元素的后一個位置
多維數組:
本質:數組的數組。常把第一維叫 行,第二維度叫 列。
初始化:用一個花括號初始化(全部的值放一起,逗號隔開,個數 <= 行 * 列,舉例:int ia[3][4]= {1, 2, 3, 4 },顯式初始化了第一行,剩下的被初始化為0),或者用多個花括號初始化(同樣最外層的大括號少不了,但是里層就是一個大括號表示一行的初始化,舉例:int ia[3][4]= { {1}, { 2}, {3} },顯式初始化了每一行的第一個元素,剩下的被初始化為0)
對多維數組進行處理的三種方式:下標、范圍for 和 指針。
a. 下標:
constexpr size_t row = 3, col=4; int ia[ row ][ col ] ; // 二維數組未被初始化
for (size_t i = 0; i != row; i++) // 對每一行
for (size_t j = 0; j != col; j++) // 對行內每一列
ia [ i ][ j ] = i * col + j;
b. 范圍 for
constexpr size_t row = 3, col=4; int ia[ row ][ col ] ; // 二維數組未被初始化 for (auto &r : ia) // 對每一行,即外層數組的每一個元素 for (auto &c : r ) {// 對行內每一列,即內層數組的每一個元素 c = cnt; cnt++;
}
預備:程序使用數組名時,會自動將其轉換成指向數組首個元素的指針。
第一個 for 遍歷 ia 的每一個元素,這些元素是大小為4的數組,所以r 的類型為含有4個元素的引用。
第二個 for 遍歷 r 的每一個元素,這些元素類型為整形,所以 c 的類型為整形的引用。
即使第二個for 循環里不對數組的元素進行寫操作,不改變他們的值,第一個for循環 r 也要用引用的形式?為什么:
因為第一個for循環遍歷 ia 的每一個元素,這些元素是大小為4 的數組,若 r 不是引用,編譯器初始化 r 時會將這些數組形式的元素(像其他類型的數組一樣)自動轉換成指向這些數組內首元素的指針,這樣得到的 r 的類型就是 int*,這樣第二層循環編譯器試圖在一個int* 內遍歷,這顯然是不對的,
所以:要使用范圍for 語句處理多維數組,除了最內層的循環外,其他所有循環的控制變量都應該是 引用 類型。 -- 《C++ primer》
c. 指針和多維數組
// 讀取二維數組 ia [ 3 ][ 4 ]中的每個值
for ( auto p = ia; p != ia + 3; ++p){ for (auto q = *p; q != *p + 4; ++p) cout << *q << ' '; cout << endl; }
預備:
int ia [ 3 ][ 4 ];
int (*p)[4] = ia; // ia 被轉換為指向 ia 內三個 數組 元素的首地址,按照《C++ primer》的說法,從內往外的順序來理解這個表達式
// (*p) 表示p 是個指針,再看右邊, 可知p 是指向大小為 4 的數組的指針,再看右邊,這個數組的元素的類型為 int ,這樣就可以知道 p 指向含有四個整數的數組。
//
int *p[4]; // p 是整形指針的數組
有了這個基礎就可以解釋上面的代碼了。C11的新標准,可以使用auto就能盡可能的避免在數組前面加上一個指針類型了,
即:auto p = ia(和 int (*p)[4] = ia;是一樣的);auto q = *p; p 是指向一個含有4個整數的數組,那么*p 就是一個含有4元素的數組,所以*p被自動地轉換成指向該數組首元素的指針,這就解釋了為什么 內層for 循環 的判別條件為 q != *p + 4;
附:《C++primer》習題 3-43
三種不同版本輸出二維數組的元素(不能使用 類型別名 或 auto 或 decltype):
// 范圍 for
cout<< "range for :" <<endl; for(const int (&row)[4] : ia) { for(int col : row) cout << col << " "; cout << endl; } // 普通for,使用下標
cout<< "普通for,使用下標" <<endl; for(size_t i = 0; i != 3; ++i) { for(size_t j = 0; j!= 4; ++j) cout << ia[i][j]<< " "; cout <<endl; } // 普通for,使用指針
cout << " 普通for,使用指針 " <<endl; for(int(*row)[4] = ia; row != ia + 3; ++row) { for(int *col = *row; col != *row +4; ++col) cout << *col<<" "; cout << endl; }
使用類型別名替代循環控制變量的類型:
using int_array = int[4]; // 范圍 for
cout<< "range for :" <<endl; for(int_array&row : ia) { for(int col : row) cout << col << " "; cout << endl; } // 普通for,使用下標
cout<< "普通for,使用下標" <<endl; for(size_t i = 0; i != 3; ++i) { for(size_t j = 0; j!= 4; ++j) cout << ia[i][j]<< " "; cout <<endl; } // 普通for,使用指針
cout << " 普通for,使用指針 " <<endl; for( int_array *row = ia; row != ia + 3; ++row) { for(int *col = *row; col != *row +4; ++col) cout << *col<<" "; cout << endl; }
使用類型別名:
// 范圍 for
cout<< "range for :" <<endl; for(auto &row : ia) { for(int col : row) cout << col << " "; cout << endl; } // 普通for,使用下標
cout<< "普通for,使用下標" <<endl; for(size_t i = 0; i != 3; ++i) { for(size_t j = 0; j!= 4; ++j) cout << ia[i][j]<< " "; cout <<endl; } // 普通for,使用指針
cout << " 普通for,使用指針 " <<endl; for( auto *row = ia; row != ia + 3; ++row) { for(int *col = *row; col != *row +4; ++col) cout << *col<<" "; cout << endl; }