看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《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:陣列和指標 可以參考這篇 #1ERylPtG (C_and_CPP) 08/05 23:48
maerdimer:我看過有網頁寫 "陣列本身就是一種指標" 嗯.... 08/06 00:02
thinklu:很仔細~推!! 08/06 06:15
acess23:下面那段學c++到底怎麼了?? 08/06 19:49
zebraseven:我真的看不懂 purpose 在這兩篇是在回什麼東西 05/29 01:02