簡析指針與多維數(shù)組三 28 bigwhite技術(shù)志 Array, Blog, Blogger, C, C專家編程, Pointer, Programmer, 內(nèi)存, 博客, 多級指針, 多維數(shù)組, 學(xué)習(xí), 工作, 思考, 指針, 數(shù)組, 程序員, 編程 4 Comments 上一篇文章中對多級指針做了簡要分析,,其實(shí)只有當(dāng)指針與多維數(shù)組以及函數(shù)聯(lián)合在一起使用時,麻煩才算真正到來,。 零,、數(shù)組與數(shù)組名 C語言中的數(shù)組的一般聲明形式如下: T arr_name[n]; /* T為類型,n為數(shù)組元素個數(shù) */ 從內(nèi)存布局角度來說,,數(shù)組T arr_name[n]就是內(nèi)存中連續(xù)的內(nèi)存單元,,每個內(nèi)存單元的長度為sizeof(T),數(shù)組的起始內(nèi)存單元地址為arr_name所在的內(nèi)存地址,, 同時也是數(shù)組第一個元素arr_name[0]的內(nèi)存地址,。 C語言數(shù)組的數(shù)組名(arr_name)有這樣的特點(diǎn):arr_name = &arr_name = *arr_name = 數(shù)組起始地址。見下面例子: char a[5]; printf("a = %p\n", a); 輸出結(jié)果: a = 0xbfb146c0 C語言數(shù)組與指針有著緊密的聯(lián)系,。數(shù)組名本身的值就是數(shù)組的起始地址,,有了地址,就有了指針存在的理由了,。 1) 數(shù)組名可以被當(dāng)作指針來用 char a[5] = {1, 2, 3, 4, 5}; 2) 數(shù)組名可以作為地址被賦值給兼容類型的指針變量 3) 數(shù)組名不可以被當(dāng)作指針變量來賦值 char a[5] = {1, 2, 3, 4, 5}; a = b; //編譯器提示錯誤:將‘char *’賦值給‘char[5]’時類型不兼容 數(shù)組名與指針變量不同:指針變量有單獨(dú)的存儲空間,,其存儲空間內(nèi)存儲的是指向的內(nèi)存單元的地址,,但數(shù)組名只是個"代號"而已,其沒有單獨(dú)的存儲空間,,其所 在內(nèi)存地址中存儲的是數(shù)組第一個元素的元素值,,而不是一個地址?;蛘哒f數(shù)組名代表的是一個值類型,,char a[5]中的a可理解為是一個char[5]的值類型變量。將一個數(shù)組指針變量值賦值給一個值變量顯然是不合邏輯的,,也是非法的,。 4) 考慮到效率,數(shù)組無法被按值傳遞給函數(shù) 正如4)中所言,,數(shù)組是以傳址方式傳入函數(shù)的,。對于以數(shù)組變量作為形參的函數(shù)來說,在函數(shù)內(nèi)部引用該參數(shù)時,,會自動將該參數(shù)視為數(shù)組類型兼容的指 針變量,,比如: void foo(char a[5]) { 這是一個經(jīng)典的C語言“陷阱”。foo形參中變量a已經(jīng)轉(zhuǎn)化為一個char*類型指針了,。對該指針變量進(jìn)行sizeof操作,,所得的 size僅是一個指針的長度(在32bit編譯下是4),而不是a數(shù)組的長度(4 * 5),。 一,、多維數(shù)組的理解 C語言中管數(shù)組的數(shù)組(的數(shù)組的…)稱為多維數(shù)組,雖然高于二維的多維數(shù)組并不經(jīng)常使用和遇見,。 T multi_arr_name[i][j][k]; 多維數(shù)組也是數(shù)組,,根據(jù)數(shù)組的理解,多維數(shù)組也是內(nèi)存中連續(xù)分配的內(nèi)存單元,,只是這些物理分配的內(nèi)存單元被從邏輯上看成是“行”,、“列”以及各種 維度罷了?!?a >C專家編程》中有一種理解方法:將數(shù)組看成是一種向量,,也就是某種對象的一維數(shù)組;當(dāng)其元素為其他數(shù)組時,,這個向量也就是我們所說的 多維數(shù)組,。 我們來結(jié)合例子理解一下多維數(shù)組,從低維到高維度逐步理解: 1) 一維數(shù)組 char a[2]; char a[2]; <=> (char) a[2]; 2) 二維數(shù)組 char a[2][3]; char a[2][3]; <=> (char[3]) a[2]; 3) 三維數(shù)組 char a[2][3][5]; char a[2][3][5]; <=> (char[3][5]) a[2]; 4) N維數(shù)組 char a[i][j][k]…[z]; char a[i][j][k]…[z]; <=> (char [j][k]…[z]) a[i]; 二,、與數(shù)組類型兼容的指針類型 假設(shè)有下面這樣一個數(shù)組: char a[2][3]; 我要聲明一個可以指向該數(shù)組的指針變量,這個聲明該如何書寫呢,?是 char *p[3]還是char (*p)[3],?按照上面對多維數(shù)組的理解: char a[2][3]; <=> char[3] a[2]; 這樣我們只需構(gòu)造出一個指向char[3]類型的指針即可,顯然這樣的指針聲明是(char[3]) *p,。哦,,不對,這樣的聲明C編譯器是不認(rèn)的,,乾坤大挪移,!把(char[3])從中間劈開 => char *p[3],這樣對么,?這個是指向數(shù)組a的指針么,?怎么越看越像是一個指針數(shù)組阿,char *p[3]<=> (char*) p[3],。哇,,真的弄錯了,改,! 對了,,剛才忘記了(char[3]) *p中還有一對括號呢,給*p穿上,,=> char (*p)[3],。這回沒錯了,就是它了,。 char a[2][3]; p = a; /* 沒有什么比這個還正確的了 */ 再來一個三維數(shù)組的例子,,這次簡單直白點(diǎn)。 char a[2][3][5]; 變形,!=> (char[3][5]) a[2]; 有了上面的例子分析,,對于更高維度數(shù)組,你還不會聲明其兼容的指針類型嗎,? 理解了多維數(shù)組兼容的指針變量的類型聲明,,那么將多維數(shù)組與函數(shù)結(jié)合在一起使用時,你就會得心應(yīng)手了,,在函數(shù)內(nèi)部你看到的,、能用到的就是多維數(shù)組 對應(yīng)的兼容指針類型變量。 三,、多維數(shù)組中的“隱式數(shù)組名” 在很多C語言書中,,我們會經(jīng)常看到這樣的描述:對于多維數(shù)組char a[m][n][h],其中的某個元素a[i][j][k] <=> *(*(*(a + i) + j) + k),。這種等價形式是如何形成的呢,? 第零小節(jié)的描述告訴我們:數(shù)組名是具有指針屬性的,除了標(biāo)準(zhǔn)的下標(biāo)引用方式外,,還可以以指針的方式做指針運(yùn)算以及訪問元素,,這就是 *(*(*(a + i) + j) + k)是合法的原因。 接下來我們來對*(*(*(a + i) + j) + k)做一次分解分析,。鑒于一般形式不易理解和輸出結(jié)果,,我們用一個具體的例子來說明。 char a[2][3][5] = { { char (*p)[3][5] = a; 編譯這個程序,,執(zhí)行輸出: a[1][2][3] = 34 我們以*(*(*(a + 1) + 2) + 3)為例,,再根據(jù)上面的輸出結(jié)果,逐步拆解分析,。 1) a + 1 a的等價指針類型是char (*p)[3][5]; 因此a + 1這個指針運(yùn)算的結(jié)果相當(dāng)于在數(shù)組a的起始地址開始向后移動sizeof(char [3][5])個字節(jié),。從輸出結(jié)果來看,a + 1 = 0xbfa0894d = 0xbfa0893e + 15 = a addr +15也印證了這點(diǎn),。 2) *(a + 1) 通常指針的解引用操作會得到指針?biāo)竷?nèi)存地址所在存儲單元中存儲的值,。但上面的輸出結(jié)果讓我們產(chǎn)生疑問: *(a + 1) = 0xbfa0894d == a + 1 在若干年前我的文章《挖掘一下C語言中的多維數(shù)組》中曾經(jīng)探討過這個問題,當(dāng)時針對這個問題并未給出答案,。這次對此問題我又有了新的認(rèn)識,。還記得我們在開篇中對數(shù)組名做的操作以及輸出結(jié)果么: char a[5]; a = 0xbfb146c0 也是a == *a。而這里同樣是*(a + 1) == a + 1,。通過這個對比我們得到一個大膽的推論:a + 1也可以看作是一個“數(shù)組名”,,這是一個隱式數(shù)組名。只有這個解釋看起來是合理的,。 3) *(a + 1) + 2 a + 1這個隱式數(shù)組名對應(yīng)的指針類型是char (*p)[5],,因此 *(a+1) +2相當(dāng)于從a + 1地址的開始再向后移動10(2 x 5)個字節(jié),也就是0xbfa08957,,輸出結(jié)果也印證了這點(diǎn),。 4) *(*(a + 1) + 2) 我們又遇到了一個隱式數(shù)組名。*(*(a + 1) + 2) = 0xbfa08957 == *(a + 1) + 2,。 5) *(*(a + 1) + 2) + 3 *(a + 1) + 2這個隱式數(shù)組名對應(yīng)的指針類型是char *p,,因此*(*(a + 1) + 2) + 3相當(dāng)于從*(a + 1) + 2開始再向后移動3個字節(jié),也就是0xbfa0895a,,注意這個地址所在單元上存儲的是一個char值,。 6) *(*(*(a + 1) + 2) + 3) 如果將*(*(a + 1) + 2) + 3賦值給char *p,,那么*(*(*(a + 1) + 2) + 3)就相當(dāng)于*p,,這個再簡單不過了,34就是這個單元存儲的char值。 2013, bigwhite. 版權(quán)所有. Related posts: |
|