2010-07-06 84 views
2

這不是一個問題,「我如何將它傳遞給函數?」而是,「這可以接受嗎?」On將2D陣列傳遞給函數

void func(int **ptr); 

int main(int argc, char* argv[]) 
{ 
    int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}}; 
    int *pArr = *arr; 

    (&pArr[0])[1] = 3; 

    func(&pArr); 

    cin.get(); 
    return 0; 
} 

void func(int **ptr) 
{ 
    cout << "In func()" << endl; 
    ptr[0][1] = 5; 
} 

這可以工作,據我所知。它對我來說並不安全,但我更喜歡它將2D數組傳遞給函數。相反,一個指針可以爲我完成這項工作。

這對於那些必須閱讀我的代碼的人來說會非常困惑嗎?我應該使用其他方法嗎?使用指向數組的指針是不是一個好主意?

此外,問題有點偏題。我爲什麼可以這樣寫:

int arr[] = { 1, 2, 3, 4, 5 }; 
int *pArr = *arr; 

但爲什麼我不能寫

int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}}; 
int *pArr = **arr; 

甚至用**帕爾?

回答

4

讓我們仔細分析一下,因爲數組到指針的轉換有時會令人困惑。

int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}}; 

arr現在是3個3個數組的數組的數組。

int *pArr = *arr; 

*arr使用數組ARR中表達,所以它衰減到指針ARR的第一個元素 - 即指針的3個整數陣列(包含數組{1,2,0})。取消引用該指針(使用*)將爲您提供3個整數的數組。現在你在表達式中使用表示數組,並且它衰減到指向int的指針,該int指向pArr。

(&pArr[0])[1] = 3; 

pArr[0]給出了pArr指向的整數(數字1)。 &pArr[0]在該整數處產生指針(其實際上等於pArr)。使用[1]對指針進行索引給出對數字1之後的下一個整數的引用,該數字是數字2.將該引用指定爲3.以下是catch:指向數組元素的指針只能用於訪問同一陣列的其他元素。在數組{1,2,0}的元素,你已經改變了你的指針指向{1,3,0},這很好,但

func(&pArr); 

現在你正在創建一個指針指向int(因爲pArr是指向int的指針),並將其傳遞給函數。

ptr[0][1] = 5; 

現在你已經採取了ptr[0],其計算結果爲指向的對象,這是你原來的指針帕爾。此行相當於pArr[1] = 5;,這仍然有效(將您的{1,2,0}數組更改爲{1,5,0})。然而,ptr[1][...將是無效的,因爲ptr未指向任何種類的數組。它指向一個獨立的指針。增加ptr會使它指向未初始化的內存並且取消引用,這將是未定義的行爲。

而對於其他問題:

你不應該能夠這樣寫:

int arr[] = { 1, 2, 3, 4, 5 }; 
int *pArr = *arr; 

數組arr衰減到指針到INT(在1號指點),非關聯化給出整數,並且整數不能被分配給指針pArr。 gcc說錯誤:從'int'無效轉換爲'int'*。 同樣地,也可以不寫此:

int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}}; 
int *pArr = **arr; 

出於同樣的原因:* ARR是3個整數{1,2,... 0},** ARR是整數1,以及整數不能被分配在陣列到一個指針。

6

您在這裏感到困惑。 int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}};而不是指向長度爲3的數組的指針。它是單個固態存儲器塊,其長度衰減爲單個int*。編譯器爲你執行一個3 * first + second映射到這個單獨的內存塊。

原因函數中的下標無效是因爲函數無法確定數組的尺寸是什麼。使用單維數組,您不需要此信息 - 只需將索引添加到給定的基址指針即可。但是,對於二維數組,需要維度來計算最終索引。

ptr[0][1] = 5;在你的功能正在被譯成*((*(ptr + 0)) + 1) = 5;,這顯然不是你想要給什麼arr不是指針數組。

編輯:在迴應評論:

ptr[0][1] does overwrite the information in cell [0][1] of the array

是的,你真的很幸運在這裏 - 這裏的原因。當你將數組傳遞給你的函數時,你通過了(&pArr[0])[1],這是一個指向數組第一個元素的指針。當你做了*((*(ptr + 0)) + 1) = 5;,ptr+0變爲空操作,離開*(*ptr + 1) = 5;,根據你的輸入數據(它看作arr作爲單維數組),它確實有明確的行爲。如果你試圖改變下標的第一個維度,那麼它會炸燬。

+0

感謝您的信息,但我不完全理解你的意思。 ptr [0] [1]確實覆蓋了數組的單元[0] [1]中的信息,那麼這不是我想要的? 然後,如果數組僅僅是一個9個單元的塊,那麼我真的可以使用一個指向數組的元素0..7的指針,而不是這樣做嗎?所以我基本上過分複雜的整個事情? – IAE 2010-07-06 12:30:48

+0

@SoulBeaver:是的。 'arr'衰變成一個'int *',而不是'int **'。我在回答中回覆了您評論的第一部分。 – 2010-07-06 12:42:14

+2

我已經低估了這個答案,因爲答案和回答者關於衰變的評論都是錯誤的。 'arr'不是一個指向內存的指針,但它本身就是一個內存塊(如果它是一個指針,它不需要衰減)。它衰變爲'int(*)[3]',而不是'int *'。對於這個問題,我想說整個'(&pArr [0])[1]'和'pArr [1]'是一樣的。我懷疑他想編寫'(&pArr)[0] [1]'來模擬在函數中完成的訪問。但是他的整個代碼對我來說沒有意義。我懷疑他很困惑。請更正答案,我會收回我的downvote,隊友。 – 2010-07-06 13:05:09

-1

我發現C++中的多維數組總是有點混亂,並且往往會避免它們。有幾種解決方案比較容易理解,例如Boost.MultiArray或Boost.UBlas庫中的類,或矢量矢量,這取決於您的需求。