C++?多維數(shù)組詳解
3.6 多維數(shù)組
其實(shí)C++中沒(méi)有什么多維數(shù)組,所說(shuō)的多維數(shù)組其實(shí)就是數(shù)組的數(shù)組。
當(dāng)一個(gè)數(shù)組的元素依舊是數(shù)組時(shí),通常使用兩個(gè)維度來(lái)定義它:一個(gè)維度表示數(shù)組本身大小,另外一個(gè)維度表示其元素(數(shù)組的數(shù)組)大寫(xiě):
int ia[3][4];
大小為3的數(shù)組,每個(gè)元素是含有4個(gè)整數(shù)的數(shù)組。
int arr[10][20][30] = {0};
大小為10的數(shù)組,它的每個(gè)元素都是大小為20的數(shù)組,這些數(shù)組的元素又包含30個(gè)整數(shù)的數(shù)組,最后將所有元素初始化為0。
由內(nèi)到外的順序閱讀此類(lèi)定義有助于更好地理解其真實(shí)含義。在第一條語(yǔ)句中,定義名稱(chēng)為ia,顯然ia是一個(gè)含有3個(gè)元素的數(shù)組。再往右邊寫(xiě)著ia的元素的維度,所以ia的元素本省又是含有4個(gè)元素的數(shù)組。在觀察最左邊,就能知道真正儲(chǔ)存的元素(ia的元素的數(shù)組)是整數(shù)。因此最后可以明確第一條語(yǔ)句的含義:定義了一個(gè)大小為3,名為ia的數(shù)組,該數(shù)組的每個(gè)元素都是含有4個(gè)整數(shù)的數(shù)組。
再用同樣的方式理解第二條arr的定義,首先arr是一個(gè)大小為10的數(shù)組,它的每個(gè)元素都是大小為10的數(shù)組,而這些數(shù)組的元素又都是含有30個(gè)整數(shù)的數(shù)組。并且,定義數(shù)組時(shí)對(duì)下標(biāo)運(yùn)算符的數(shù)量并沒(méi)有限制,因此只要愿意就可以定義一個(gè)數(shù)組,它的元素是數(shù)組,數(shù)組的元素又是數(shù)組(禁止套娃?。?/p>
對(duì)于二維數(shù)組來(lái)說(shuō),常吧第一個(gè)維度成為行,第二個(gè)維度稱(chēng)為列。
多維數(shù)組的初始化
允許使用花括號(hào)括起來(lái)的一組值初始化多維數(shù)組,這點(diǎn)和普通的數(shù)組一樣。下面初始化形式中,多維數(shù)組的每一行分別用花括號(hào)括了起來(lái):
int ia[3][4]= //三個(gè)元素,每個(gè)元素都是大小為4的數(shù)組 { {0,1,2,3}, //第1行的初始值 {4,5,6,7}, //第2行的初始值 {8,9,10,11} //第3行的初始值 };
其中內(nèi)層嵌套的花括號(hào)并非必需的,例如下面的初始化語(yǔ)句,形式上更為簡(jiǎn)潔,完成的功能和上面的代碼完全一致:
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11}; //沒(méi)有標(biāo)識(shí)每行的花括號(hào),與之前的初始化語(yǔ)句是等價(jià)的
類(lèi)似一維數(shù)組,在初始化多維數(shù)組時(shí)也并非所有元素的值都必須包含在初始化表之內(nèi)。如果僅僅想初始化每一行的第一個(gè)元素,通過(guò)如下的語(yǔ)句:
int ia[3][4] = {{0},{4},{8}}; //顯式地初始化每行的首元素
其他沒(méi)有列出的元素執(zhí)行默認(rèn)初始化,這個(gè)過(guò)程和一位數(shù)組一樣。此時(shí)如果去掉內(nèi)層花括號(hào),結(jié)果就不同了。
int ix[3][4] = {0,3,6,9}; //顯式地初始化第1行,其他元素執(zhí)行值的初始化。
此時(shí)的含義是,它初始化了第一行的4個(gè)元素,其他元素被初始化0。
多維數(shù)組的下標(biāo)引用
可以使用下標(biāo)運(yùn)算符來(lái)訪(fǎng)問(wèn)多維數(shù)組的元素,此時(shí)數(shù)組的每個(gè)維度都對(duì)應(yīng)一個(gè)下標(biāo)運(yùn)算符。
如果表達(dá)式含有的下標(biāo)運(yùn)算符數(shù)量和數(shù)組的維度一樣多,該表達(dá)式的結(jié)果將是給定類(lèi)型的元素;舉個(gè)例子:arr[0][0][0]的下標(biāo)運(yùn)算符數(shù)量為3,并且arr是3維的,此時(shí)下標(biāo)運(yùn)算符數(shù)量和數(shù)組的維度就是一樣多了。
反之,如果表達(dá)式含有的下標(biāo)運(yùn)算符數(shù)量比數(shù)組的維度小,則表達(dá)式的結(jié)果將是定索引的一個(gè)內(nèi)層數(shù)組:
ia[2][3] = arr[0][0][0]; //用arr的首元素為ia最后一行的最后一個(gè)元素賦值 int (&row)[4] = ia[1]; //把row綁定到ia的第二個(gè)4元素?cái)?shù)組上
在第一個(gè)例子中,對(duì)于用到的兩個(gè)數(shù)組來(lái)說(shuō),表達(dá)式提供的下標(biāo)運(yùn)算符數(shù)量和它們各自的維度相同。在等號(hào)左側(cè),ia[2]得到數(shù)組ia的最后一行,此時(shí)返回的是表達(dá)ia最后一行的那個(gè)一維數(shù)組而并非任何實(shí)際元素;對(duì)于這個(gè)一維數(shù)組再去取下標(biāo),得到編號(hào)為[3]的元素,也就是這行的最后一個(gè)元素。
經(jīng)常使用for循環(huán)來(lái)處理多維數(shù)組的元素,二維數(shù)組大多數(shù)就兩層嵌套的for循環(huán)去處理,外層for循環(huán)處理行,內(nèi)層for循環(huán)處理列;三維數(shù)組中,最外層循環(huán)表示面,中間層表示行,最內(nèi)層表示列。以此遍歷數(shù)組:
constexpr size_t rowCnt = 3 , colCnt = 4; int ia[rowCnt][colCnt]; for(size_t i = 0;i != rowCnt;++i) { for(size_t j = 0;j != colCnt;++j) { ia[i][j] = i * colCnt + j; } }
使用范圍for語(yǔ)句處理多維數(shù)組
由于在C++11新標(biāo)準(zhǔn)中新增了范圍for語(yǔ)句,所以前一個(gè)程序可以簡(jiǎn)化為如下形式:
size_t cnt = 0; for (auto &row : ia) { for(auto &col : row) { col = cnt; ++cnt; } }
ia是一個(gè)由數(shù)組構(gòu)成的數(shù)組,每次遍歷,相當(dāng)于一行一行的遍歷了ia。所以每次遍歷row相當(dāng)于取出一行ia。相當(dāng)于:對(duì)于外層數(shù)組的每一個(gè)元素。
而col又相當(dāng)于每一行的row的引用。相當(dāng)于:對(duì)于內(nèi)層數(shù)組的每一個(gè)元素。
這個(gè)循環(huán)賦值給ia元素的值和之前的那個(gè)循環(huán)是完全相同的,區(qū)別在于通過(guò)使用范圍for語(yǔ)句把管理數(shù)組索引的任務(wù)交給了系統(tǒng)。因?yàn)橐淖冊(cè)氐闹担缘冒芽刂谱兞縭ow和col聲明成引用類(lèi)型。 第一個(gè)for循環(huán)遍歷ia的所有元素,這些元素是大小為4的數(shù)組,因此row的類(lèi)型就應(yīng)該是含有4個(gè)整數(shù)的數(shù)組的引用。 第二個(gè)for循環(huán)遍歷那些4個(gè)元素?cái)?shù)組中的某一個(gè),因此col的類(lèi)型是整數(shù)的引用。每次迭代把cnt的值賦給ia的當(dāng)前元素,然后將cnt加1。
在上面的例子中,因?yàn)橐淖償?shù)組元素的值,所以我們選用引用類(lèi)型作為循環(huán)控制變量,但是其實(shí)還有一個(gè)深層次的原因促使我們這么做。
for(const auto &row:ia) for(auto col:row) cout<<col<<endl;
這個(gè)循環(huán)中并沒(méi)有任何寫(xiě)操作,但是我們還是將外層循環(huán)的控制變量聲明成了引用類(lèi)型,這是為了 避免數(shù)組ia被自動(dòng)轉(zhuǎn)換成指針 。
for(auto row:ia) for(auto col:row)
此時(shí)ia被自動(dòng)轉(zhuǎn)化成指針,row也變成指針了,auto col:row就變成col遍歷row的每一個(gè)地址。但是我們又不要遍歷地址。所以外層的引用方式必須要加的。
程序無(wú)法通過(guò)編譯。這是因?yàn)?,想之前一樣第一個(gè)循環(huán)遍歷ia的所有元素,注意這些元素實(shí)際上是大小為4的數(shù)組。因?yàn)閞ow不是引用類(lèi)型,所以編譯器初始化row時(shí)會(huì)自動(dòng)將這些數(shù)組形式的元素(和其他類(lèi)型的數(shù)組一樣)轉(zhuǎn)換成指向該數(shù)組內(nèi)首元素的指針。這樣會(huì)得到的row的類(lèi)型就是int*,顯然內(nèi)層的循環(huán)就不合法了,編譯器將試圖在一個(gè)int*內(nèi)遍歷,這顯然和程序的初衷不一樣。
Tips:要使用范圍for語(yǔ)句處理多維數(shù)組,除了最內(nèi)層的循環(huán)外,其他所有循環(huán)的控制變量都應(yīng)該是引用類(lèi)型。
指針和多維數(shù)組
當(dāng)程序使用多維數(shù)組的名字時(shí),也會(huì)自動(dòng)將其轉(zhuǎn)換成指向數(shù)組首元素的指針。
因?yàn)槎嗑S數(shù)組實(shí)際上是數(shù)組的數(shù)組,所以由多維數(shù)組名轉(zhuǎn)換而來(lái)的指針實(shí)際上是指向第一個(gè)內(nèi)層數(shù)組的指針:
int ia[3][4]; //大小為3的數(shù)組,每個(gè)元素是含有4個(gè)整數(shù)的數(shù)組 int (*p)[4] = ia; //p指向含有4個(gè)整數(shù)的數(shù)組 p = &ia[2]; //p指向ia的尾元素。
(*p)意味著p是一個(gè)指針。接著看右側(cè),指針p指向的是一個(gè)維度為4的數(shù)組;再看左側(cè)可知,數(shù)組中的元素是整數(shù)。所以,p是指向含有4個(gè)整數(shù)的數(shù)組的指針。
//在上述聲明中,圓括號(hào)必不可少: int *ip[4]; //整形指針的數(shù)組 int (*ip)[4]; //指向含有4個(gè)整數(shù)的數(shù)組
隨著C++11新標(biāo)準(zhǔn)提出,通過(guò)使用auto或者decltype就能盡可能地避免在數(shù)組前面加上一個(gè)指針類(lèi)型了:
//輸出ia中每個(gè)元素的值,每個(gè)內(nèi)層數(shù)組各占一行 //p指向含有4個(gè)整數(shù)的數(shù)組 for(auto p = ia;p != ia + 3; ++p) { //q指向4個(gè)整數(shù)數(shù)組的首元素,也就是說(shuō),q指向一個(gè)整數(shù) for(auto q = *p; q != *p + 4;++q) cout << *q <<' '; cout<<endl; }
外層的for循環(huán)首先聲明了一個(gè)指針并且令其指向ia的第一個(gè)內(nèi)層數(shù)組,然后依次迭代直到ia的全部3行都處理完為止。其中遞增運(yùn)算++p負(fù)責(zé)將指針p移動(dòng)到ia的下一行。
內(nèi)層的for循環(huán)負(fù)責(zé)輸出內(nèi)層數(shù)組所包含的值。它首先令指針q指向p當(dāng)前所在行的第一個(gè)元素。*p是一個(gè)含有4個(gè)數(shù)組的數(shù)組,像往常一樣,數(shù)組名被自動(dòng)地轉(zhuǎn)換成指向該數(shù)組首元素的指針。內(nèi)層for循環(huán)不斷迭代直到我們處理完了當(dāng)前內(nèi)層數(shù)組的所有元素為止。為了獲取內(nèi)層for循環(huán)的終止條件,再一次解引用p得到指向內(nèi)層數(shù)組首元素的指針,給它加上4就得到了終止條件。
當(dāng)然,使用標(biāo)準(zhǔn)庫(kù)函數(shù)begin和end也能實(shí)現(xiàn)同樣的功能,而且看起來(lái)更簡(jiǎn)潔一些:
//p指向ia的第一個(gè)數(shù)組 for(auto p = begin(ia); p != end(ia); ++p) { //q指向內(nèi)層數(shù)組的首元素 for(auto q = begin(*p); q != end(*p); ++q) cout<< *q << ' ' ; //輸出q指向的整數(shù) cout <<endl; }
在此代碼中,循環(huán)終止條件由end函數(shù)負(fù)責(zé)判斷。雖然我們能夠判斷出p和q的類(lèi)型,但是直接使用auto關(guān)鍵字我們就不必再操心這些類(lèi)型是什么了。
類(lèi)型別名簡(jiǎn)化多維數(shù)組的指針
讀,寫(xiě)和理解一個(gè)指向多維數(shù)組的指針是讓人不勝其煩的工作,使用類(lèi)型別名能讓工作變得簡(jiǎn)單一點(diǎn)。
using int_array = int[4]; //新標(biāo)準(zhǔn)下類(lèi)型別名的聲明 typedef int int_array[4]; //等價(jià)typedef聲明 //輸出ia中每個(gè)元素的值,每個(gè)內(nèi)層數(shù)組各占一行 for(int_array *p = ia; p != ia + 3;++q) { for (int *q = *p;q != *p + 4; ++q) cout<< *q <<' '; cout<<endl; }
程序?qū)㈩?lèi)型“4個(gè)整數(shù)組成的數(shù)組” 命名為int_array,用類(lèi)型名int_array定義外層循環(huán)的控制變量讓程序看著更簡(jiǎn)潔;
到此這篇關(guān)于C++ 多維數(shù)組詳解的文章就介紹到這了,更多相關(guān)C++ 多維數(shù)組內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++11 std::function和std::bind 的使用示例詳解
C++11中的std::function和std::bind是函數(shù)對(duì)象的重要組成部分,它們可以用于將函數(shù)和參數(shù)綁定在一起,形成一個(gè)可調(diào)用的對(duì)象,這篇文章主要介紹了C++11 std::function和std::bind 的使用示例詳解,需要的朋友可以參考下2023-03-03C/C++函數(shù)參數(shù)傳遞機(jī)制詳解及實(shí)例
這篇文章主要介紹了C/C++函數(shù)參數(shù)傳遞機(jī)制詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02C++中實(shí)現(xiàn)多態(tài)有幾種方式小結(jié)
在C++中,多態(tài)是一種面向?qū)ο缶幊痰奶匦?允許以統(tǒng)一的方式處理不同類(lèi)型的對(duì)象,并根據(jù)實(shí)際對(duì)象的類(lèi)型來(lái)執(zhí)行相應(yīng)的操作,本文給大家介紹了C++中實(shí)現(xiàn)多態(tài)有幾種方式小結(jié),需要的朋友可以參考下2024-12-12C語(yǔ)言實(shí)現(xiàn)循環(huán)打印星號(hào)圖形再鏤空
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)循環(huán)打印星號(hào)圖形再鏤空,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11VC實(shí)現(xiàn)讓關(guān)閉按鈕成灰色不可用的方法
這篇文章主要介紹了VC實(shí)現(xiàn)讓關(guān)閉按鈕成灰色不可用的方法,比較實(shí)用的一個(gè)特殊功能,需要的朋友可以參考下2014-08-08C++11新特性之隨機(jī)數(shù)庫(kù)(Random?Number?Library)詳解
相對(duì)于C++11之前的隨機(jī)數(shù)生成器來(lái)說(shuō),C++11的隨機(jī)數(shù)生成器是復(fù)雜了很多,下面這篇文章主要給大家介紹了關(guān)于C++11新特性之隨機(jī)數(shù)庫(kù)(Random?Number?Library)的相關(guān)資料,需要的朋友可以參考下2022-06-06