2015-10-18 129 views
0

我一直在閱讀大量有關分配內存的文章,我認爲我理解這個概念,但我被告知必須使用類似下面的方法:爲2d陣列分配內存c

double ** malloc_array2d(size_t m, size_t n) 
{ 
    double **A; 
    size_t i; 

    A = malloc(m * sizeof(double *));  
    if (A == NULL) 
     return NULL; 
    A[0] = (double *) malloc(m * n * sizeof(double)); 
    if (A[0] == NULL) 
    { 
     free(A); 
     return NULL; 
    } 

    for (i = 1 ; i < m ; i++) 
     A[i] = A[0] + i *n; 
    return A; 
} 

然後當然我必須在以後釋放內存 - 但我只是不太明白這種做法,更具體地說我真的不能看到最後一行會發生什麼情況,其中剩餘指針被設置到內存塊中(我已經被告知了,而且我不知道當我完成分配時如何將元素插入到矩陣/數組中)。

+1

您可以隨時谷歌.. – wrangler

+1

而且你可太consisten,你投了'的malloc()'第二次唯一不做它在所有或做它,即使它的醜陋和不必要的,但BE是一致的。 –

+0

'for'循環非常小,嘗試使用小的具體值(比如說'm = n = 2')並且只是寫出函數的作用,擴展循環迭代。爲分配的塊和指針繪製方框和箭頭......如果您仍然無法看到發生了什麼,請解釋您所瞭解的位。 – Useless

回答

1
double ** malloc_array2d(size_t m, size_t n){ 

    double **A; 
    size_t i; 

    A = malloc(m*sizeof(double *));  
    if (A == NULL) return NULL; 
    A[0]=(double *)malloc(m*n*sizeof(double)); 
    if (A[0] == NULL) {free(A); return NULL;} 
    for(i=1; i<m; i++) A[i]=A[0]+i*n; 

    return A; 
} 

讓我們一行一行:

A = malloc(m*sizeof(double *)); 

此行米雙指針分配空間。

A[0] = (double *) malloc(m*n*sizeof(double)); 

A [0]現在是記憶m * n個雙打一個塊,這是我們需要用於2D陣列的所有雙打。

for (int i = 1; i < m; i++) {A[i] = A[0] + i * n;} 

因爲每個A [I]爲n雙打塊,我們希望A [1]開始我* N從A加倍遠[0]。

因爲所有這些都在牢固的記憶中,所以我們可以做一些有趣的事情。例如,A [0] [n]與A [1] [0]完全相同。此外,因爲所有內容都在一個大塊內存中,所以爲了訪問A [i] [j],我們只需要訪問A[0] + i*j + j處的雙精度值。這比去往指向雙* B的A [i]並且找到B [j]要快得多。

內存管理是一個難以理解的話題,需要一些時間。希望這使得更多的意義上說,我希望我沒有混淆你更:)

+0

謝謝!這完全有道理:) – Linda

-2

Yo你必須使poitners指針的每個指針指向有效的malloc() ed數據。

for (int i = 0 ; i < n ; ++i) 
    A[i] = (double *) malloc(m * sizeof(double)); 

你也可以將它分配全部一次,但隨後的符號A[i][j]將無法​​正常工作。

+1

問題中的代碼確實有效。它一次分配它,然後指向分配的塊。 – interjay

+0

是的,我認爲這是我大多數時候看到的方法,當我谷歌 - 這一個是有道理的 - 但我剛剛被告知,這是「天真」的方法,並且一個更快的方法是分配一個大塊m * n的內存,然後設置然後設置指針到這塊內存 - 我的書說這樣做:) – Linda

2

通過這種形式分配的,您可以通過分配指向其他數組的數組開始,像這樣:

T **a = malloc(sizeof *a * N); // N is the number of rows 

sizeof *a相當於sizeof (T *);數組中的每個元素將成爲指向T的指針。當我們完成後,我們有一些像在內存中的以下內容:現在

+---+ 
a: | | a[0] 
    +---+ 
    | | a[1] 
    +---+ 
    | | a[2] 
    +---+ 
    ... 
    +---+ 
    | | a[N-1] 
    +---+ 

,對於每一元素,我們分配另一的內存塊來保存T類型的每個元素:

a[i] = malloc(sizeof *a[i] * M); // M is the number of columns 

每個a[i]的類型爲T *,所以sizeof *a[i]等於sizeof (T)

後這樣做了,我們有一些看起來像這樣的記憶:

+---+   +---------+---------+ +-----------+ 
a: | | a[0] ---> | a[0][0] | a[0][1] |...| a[0][M-1] | 
    +---+   +---------+---------+ +-----------+ 
    | | a[1] ---> | a[1][0] | a[1][1] |...| a[1][M-1] | 
    +---+   +---------+---------+ +-----------+ 
    | | a[2] ---> | a[2][0] | a[2][1] |...| a[2][M-1] | 
    +---+   +---------+---------+ +-----------+ 
    ... 
    +---+   +-----------+-----------+ +-------------+ 
    | | a[N-1]--> | a[N-1][0] | a[N-1][1] |...| a[N-1][M-1] | 
    +---+   +-----------+-----------+ +-------------+ 

所以基本上你所做的是分配的TN單獨M - 元素數組,然後你收集指針到N-T *的元素數組中的那些數組。

您可以像訪問任何普通的2D數組一樣訪問每個元素,如a[i][j];請記住,表達式a[i]定義爲*(a + i);我們從a中的地址抵消了i元素(不是字節!),然後解除引用結果。所以a[i][j]被評估爲*(*(a + i) + j)

所以,幾件事情與這種形式的分配的請記住:

  1. 陣列的「行」是不會在存儲器中連續;內存中的對象a[i][M-1](很有可能)不會是a[i+1][0]

  2. 由於每個「行」 a[i]用呼叫分配給malloc,還必須明確與之前free相應的呼叫釋放取消分配a(以相反的順序總是freemalloc)。

  3. 儘管我們可以將a當作2D數組,但它沒有數組類型,所以您無法使用sizeof a技巧來確定數組的大小;你只會得到指針類型的大小,而不是數組的總大小。所以你需要自己跟蹤數組的大小。