2010-10-16 91 views
2

我已經寫了一些在OS X 10.6上運行的C代碼,這種情況發生的很慢,所以我使用valgrind來檢查內存泄漏等。我在執行此操作時注意到的一件事:在OS X上malloc的問題

如果我分配內存以2D陣列是這樣的:

double** matrix = NULL; 
allocate2D(matrix, 2, 2); 

void allocate2D(double** matrix, int nrows, int ncols) { 
    matrix = (double**)malloc(nrows*sizeof(double*)); 
    int i; 
    for(i=0;i<nrows;i++) { 
     matrix[i] = (double*)malloc(ncols*sizeof(double)); 
    } 
} 

然後檢查矩陣的存儲器地址它爲0x0。

但是,如果我這樣做

double** matrix = allocate2D(2,2); 

double** allocate2D(int nrows, int ncols) { 
    double** matrix = (double**)malloc(nrows*sizeof(double*)); 
    int i; 
    for(i=0;i<nrows;i++) { 
     matrix[i] = (double*)malloc(ncols*sizeof(double)); 
    } 
return matrix; 
} 

這工作得很好,即返回指針到新創建的內存。

當我還有一個free2D函數釋放內存。它似乎沒有正確釋放。即指針仍然指向與釋放前相同的地址,而不是0x0(我認爲這可能是默認值)。

void free2D(double** matrix, int nrows) { 
    int i; 
    for(i=0;i<nrows;i++) { 
     free(matrix[i]); 
    } 
free(matrix); 
} 

我的問題是:我誤解了malloc/free的工作方式?否則有人可以建議發生了什麼?

亞歷

+0

是的,你誤解了自由工作。 Free將'p'指向的存儲返回到「空閒列表」,但不會改變現在指向真實內存地址的「p」,但該內存不再屬於您的應用程序。什麼suihock說。 – msw 2010-10-16 10:17:23

回答

4

不會更改,如果您希望它爲空,則必須將其明確設置爲0。

1

在C++中,您應參考:)

Allocate2D(double**& matrix...) 

傳遞指針至於發生了什麼事 - 那麼你有一個指針是NULL,可以將該指針傳遞的副本這個函數分配了內存並使用新分配的內存地址初始化指針的副本,但原始指針保持爲NULL。至於免費,你不需要通過引用傳遞,因爲只有指針的值是相關的。 HTH

由於在C中沒有引用,你可以通過指針傳遞,這是

Allocate2D(double*** pMatrix...) 
{ 
    *pMatrix = malloc(...) 
} 

和當你釋放一個指針,該指針的值再打像

Allocate2D(&matrix ...) 
+0

是的,我認爲通過參考和價值來傳遞。只是無法找出解決辦法。謝謝。 – Alex 2010-10-16 10:14:08

+0

親愛的downvoter,你能否評論一下你爲什麼downvoted? – 2010-10-16 10:16:26

+0

-1:誤導性答案 - 它是C,而不是C++。 – 2010-10-16 10:16:50

3

在第一個示例中,您只將malloc返回的指針存儲在局部變量中。函數返回時會丟失。

C語言中的通常做法是使用函數的返回值將指針傳遞給分配的對象返回給調用者。正如阿爾欽指出的那樣,你也可以通過一個指針,它指向函數應該保存其輸出:

void Allocate2D(double*** pMatrix...) 
{ 
    *pMatrix = malloc(...) 
} 

,但我想大多數人都會只要他們看到***尖叫。

你也可以考慮指針數組不是矩陣的有效實現。分別分配每行有助於內存碎片化,因爲每個分配涉及一些簿記,更不用說必須存儲的額外指針了,還有緩存未命中。每個對矩陣元素的訪問涉及2個指針解引用,而不僅僅是一個,這可以引入停頓。最後,你需要做更多的工作來分配矩陣,因爲你必須檢查每個malloc的失敗,並清除你已經完成的任何失敗的任何事情。

一種更好的方法是使用一個一維數組:

double *matrix; 
matrix = malloc(nrows*ncols*sizeof *matrix); 

然後接入元件(I,J)爲matrix[i*ncols+j]。這種潛在的缺點是乘法(對古代思想緩慢但對現代思維快速)和語法。

更好的方法不是尋求過多的普遍性。 SO上的大多數矩陣代碼不適用於需要任意矩陣大小的高級數學數學,但對於2D2,3x3和4x4是任何實際使用的唯一矩陣大小的3D遊戲。如果是這樣的話,你可以試試

double (*matrix)[4] = malloc(4*sizeof *matrix); 

,然後你可以用一個反引用作爲matrix[i][j]訪問元素(I,J)和極快的乘用常數。如果你的matrix只需要在局部範圍內或在結構內部,只是聲明爲:

double matrix[4][4]; 

如果你不與C類型系統和上面的聲明非常嫺熟,它可能是最好只包裝結構中所有的矩陣反正:

struct matrix4x4 { 
    double x[4][4]; 
}; 

隨後聲明,指針蒙上,分配等成爲了很多更熟悉。唯一的缺點是您需要執行類似matrix.x[i][j]matrix->x[i][j](取決於matrix是指向結構的指針的結構)而不是matrix[i][j]

編輯:我確實想到了一個有用的屬性,將您的矩陣實現爲行指針數組 - 它使得行的排列成爲平凡的操作。如果你的算法需要執行很多行排列,這可能是有益的。請注意,雖然小矩陣的好處不會太大,並且列置換不能通過這種方式進行優化。

+0

謝謝。我現在在valgrind內存泄漏的幫助下在n板上提出了一些建議。好極了 :) – Alex 2010-10-17 21:41:19