作者EdisonX (閉上眼的魚)
看板C_and_CPP
標題Re: [問題] 關於二維陣列的pass by ref
時間Sun Aug 5 22:15:58 2012
※ 引述《Arim (Arim5566)》之銘言:
: 各位版友好
: 在傳遞二維陣列給foo的時候:
: void foo(char str[][11]){
: }
: int main(){
: char str[11][11];
: foo(str)
: }
: 請問為什麼在foo的參數列上面
: 要用str[][11]
: 為什麼不需要指定第一個[]的upper bound 而只要去指定第二個[]的upper bound(也就是
: 指定[11])
: 謝謝各位版友的指教
提外話,這問題和 pass by reference 沒有關係。
void foo(char str[][11]){
}
這段碼最後會被 compiler 翻譯成
void foo(char (*str)[11]) {
}
str 本質上是一個指標,所以在這裡 str 取得的還是一個
address 而已,
並不是整個 array. 所有的 str[i][j] 運算都是基於這個
address 做偏移處理。
一些基本假設先確立
(1) 陣列分配必為連續且線性 < 連續是必然,線性就不確定 >
(2) CHAR_BITS = 8 < 說明方便假設, depends on compiler / machine >
(3) 陣列管理為 Major in Row < C 語言是 如此沒錯, Fortran 是 Major in Column >
(4) sizeof( void *) = 4 < 說明方便假設, depends on compiler / machine >
(5) sizeof(int) = 4
(6) 橫排為列,直排為行 < 統一用語,避免困惑 >
------------------------------
首先了解 int arr[2][3] 在記憶體配置連續的,可能這樣。
Variable Address
arr[0][0] 0x80000000
arr[0][1] 0x80000004
arr[0][2] 0x80000008
arr[1][0] 0x8000000c
arr[1][1] 0x80000010
arr[1][2] 0x80000014
首先 str[0][0] 這是此陣列第一個元素,也是開頭位址,
這個位址我稱 base address of array ,陣列之基底位址,
< 恕我在高階程式語言的書籍裡,找不到合適的稱呼,引用其他書籍的稱呼 >
代表整個 arr 之位置,也常以 str[0][0] 此位址示之,只差在型態有所不同,
但代表的數值都是 0x80000000 。
對 int arr[
2][
3] 而言,在底層下當要定址到 arr[
1][
2] 時,它的做法是
< arr[H][W] arr[R][C] >
< H 列 W 行 第 R 列, 第 C 行 >
(1) 先去找 arr 之基底位址在哪 : 0x80000000
(2) 先定位到 arr[R][0], 由於一列有 W 個元素,所以 R 列有 R*W 個元素
現在是 int arr[2][3],W=3 , 所以先定位到 arr[
1][0] 時,得到位置是
(W)
arr[
1][0] = 0x80000000 +
3 *
1 * sizeof(int) = 0x80000000 + 3*4 = 0x8000000c
(3) 再從剛剛的 arr[R][0],偏移
C ,得到 arr[R][
C]。
arr[1][
2] = 0x8000000c +
2 * sizeof(int) = 0x8000000c + 8 = 0x80000014
--------------------------------------
實際上 2,3 步驟是合併的,只是說明方便才拆開來。
從上面整個計算裡,可以得到一個結論 :
int Base[H][W]; // 宣告
Base[i][j] = 0; //
*(Base + i*W + j) = 0;
有看到了嗎?計算上從頭到尾沒有用到 H, 只有用到 W;
再換三維的看看。
int Base[X][Y][Z]; // 宣告
Base[i][j][k] = 0; //
*(Base + i*Y*Z + j*Z + k) = 0;
一樣的,三維在計算上只用到 Y, Z , 而沒用到 X。
對所有多維 array 之定址而言,這種公式是可遞推出來的,
有興趣也可想想在 4, 5 維的時候該怎麼遞推。
但無論如何遞推,只有最高維度之常數用不到,其他的都用得到。
這也是為何書上告知多維陣列初始化時,只有最高維度可不指定,
因為這裡 compiler 會幫忙算。
扣除掉最高維度之常數,其他維度之常數在計算上都用得到,
所以必須指定。
--------
敘述可能有點亂,但原理就是如此,不清楚的話可再稍畫一下圖
( 就簡單的面積計算而已 ) ,應可清楚很多。
一點意見,希望可解決疑惑。
另有誤請不吝指正,感激不盡。
--
「自從我學了 C# , 人都變聰明 , 考試都考一百分」
「自從我學了 VB , 皮膚都變好 , 人也變漂亮了 」
「自從我學了 Java , 明顯變壯 , 個子也變高了 」
「自從我學了 C++ , 內分泌失調 , 頭都禿了... 」
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.76.161
推 gg1122:佛心呀~~~ 08/05 22:45
→ legnaleurc:簡單講, 函式參數只要宣告成一維陣列, 都和指標同義 08/05 22:45
→ legnaleurc:f1(int[4]) == f2(int[5]) == f3(int[]) == f4(int*) 08/05 22:47
→ legnaleurc:二維以上陣列不能省略維度是因為它要知道指標指向元素 08/05 22:48
→ legnaleurc:的大小 08/05 22:48
→ legnaleurc:所以 f5(int[][4]) != f6(int**) 08/05 22:49
推 diabloevagto:直接記得array就是指標就好... 08/05 22:51
→ diabloevagto:基本上也可以只傳指標然後用operator[]使用 08/05 22:52
→ diabloevagto:話說,請問在stack的記憶體一定是連續? 08/05 22:53
→ diabloevagto:那如果我new出來的呢?會是連續嗎? 08/05 22:53
→ legnaleurc:arrays are not pointers ... 08/05 22:53
推 purpose:連不連續,編譯器爽就好 08/05 22:55
→ EdisonX:有很多「一定」我不敢掛保證,只能說大多是這樣 <真糟 orz> 08/05 23:16
→ diabloevagto:array不是指標(?! 話說原來我一直搞錯... 08/05 23:29
→ diabloevagto:我一直覺得array使用上是不用new的指標=.= 08/05 23:29
→ EdisonX:Expert C Programming,CH4 可詳參,標題指出 陣列!=指標。 08/05 23:37
→ diabloevagto:感謝! 08/05 23:45
→ maerdimer:我看過有網頁寫 "陣列本身就是一種指標" 嗯.... 08/06 00:02
推 thinklu:很仔細~推!! 08/06 06:15
推 acess23:下面那段學c++到底怎麼了?? 08/06 19:49
推 zebraseven:我真的看不懂 purpose 在這兩篇是在回什麼東西 05/29 01:02