Re: [問題] 關於二維陣列的pass by ref

看板C_and_CPP (C/C++)作者 (閉上眼的魚)時間13年前 (2012/08/05 22:16), 編輯推噓6(6016)
留言22則, 9人參與, 最新討論串2/2 (看更多)
※ 引述《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

08/05 22:45, , 1F
佛心呀~~~
08/05 22:45, 1F

08/05 22:45, , 2F
簡單講, 函式參數只要宣告成一維陣列, 都和指標同義
08/05 22:45, 2F

08/05 22:47, , 3F
f1(int[4]) == f2(int[5]) == f3(int[]) == f4(int*)
08/05 22:47, 3F

08/05 22:48, , 4F
二維以上陣列不能省略維度是因為它要知道指標指向元素
08/05 22:48, 4F

08/05 22:48, , 5F
的大小
08/05 22:48, 5F

08/05 22:49, , 6F
所以 f5(int[][4]) != f6(int**)
08/05 22:49, 6F

08/05 22:51, , 7F
直接記得array就是指標就好...
08/05 22:51, 7F

08/05 22:52, , 8F
基本上也可以只傳指標然後用operator[]使用
08/05 22:52, 8F

08/05 22:53, , 9F
話說,請問在stack的記憶體一定是連續?
08/05 22:53, 9F

08/05 22:53, , 10F
那如果我new出來的呢?會是連續嗎?
08/05 22:53, 10F

08/05 22:53, , 11F
arrays are not pointers ...
08/05 22:53, 11F

08/05 22:55, , 12F
連不連續,編譯器爽就好
08/05 22:55, 12F

08/05 23:16, , 13F
有很多「一定」我不敢掛保證,只能說大多是這樣 <真糟 orz>
08/05 23:16, 13F

08/05 23:29, , 14F
array不是指標(?! 話說原來我一直搞錯...
08/05 23:29, 14F

08/05 23:29, , 15F
我一直覺得array使用上是不用new的指標=.=
08/05 23:29, 15F

08/05 23:37, , 16F
Expert C Programming,CH4 可詳參,標題指出 陣列!=指標。
08/05 23:37, 16F

08/05 23:45, , 17F
感謝!
08/05 23:45, 17F

08/05 23:48, , 18F
陣列和指標 可以參考這篇 #1ERylPtG (C_and_CPP)
08/05 23:48, 18F

08/06 00:02, , 19F
我看過有網頁寫 "陣列本身就是一種指標" 嗯....
08/06 00:02, 19F

08/06 06:15, , 20F
很仔細~推!!
08/06 06:15, 20F

08/06 19:49, , 21F
下面那段學c++到底怎麼了??
08/06 19:49, 21F

05/29 01:02, , 22F
我真的看不懂 purpose 在這兩篇是在回什麼東西
05/29 01:02, 22F
文章代碼(AID): #1G7e0Yai (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1G7e0Yai (C_and_CPP)