陣列記憶體申請和釋放,指標陣列和陣列指標
一 陣列指標的空間釋放
int (*p)[3] = new int [4][3];
// ...
delete []p; //---1
delete[](*p); //---2
在釋放這個二維陣列時,應該使用1和2哪種方式呢?哪種對呢?
其實兩種方法都是可以的,二維陣列,p 和 *p 指向的位置相同的,都是指向第一個元素的地址是 &p[0][0]對於C/C++如何檢測記憶體洩露,就是簡單的庫呼叫,這裡不贅述,詳見下面程式碼和參考文獻,不過注意,檢測結果的資訊輸出是在除錯的情況下檢視輸出視窗(output)的
#define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #include <stdio.h> void main() { int (*p)[3] = new int [4][3]; //delete []p; delete[](*p _CrtDumpMemoryLeaks();//除錯執行到該步,輸出檢測資訊 }
執行如程式碼所示,對於兩種釋放方式,都沒有檢測出記憶體洩露,說明這兩種方式都是正確的。
二 動態二維陣列的申請和釋放動態二維陣列有兩種形式,一種是指標陣列,一種是陣列指標
按照我自己的簡單的理解:
指標陣列,就是先申請一個指向陣列的指標陣列,然後再對每一個指標內部申請陣列,一共有兩次申請記憶體的過程
陣列指標,就是一次性申請記憶體,直接獲得一個二維陣列的全貌
二者在記憶體的物理空間上是具有不同的表現形式的,如圖所示,本節我們就簡單討論下。
#include <stdio.h> void main() { int * a = new int [3]; printf("一維陣列:\na:\t%d\n*a:\t%d\n&a[0]:\t%d\n\n" ,a,*a,&a[0]); // 使用指標陣列 int **ptr = new int*[4]; for(int i = 0; i < 4; ++i) { *(ptr+i) = new int [3]; } printf("指標陣列一步步申請:\nptr:\t%d\n&ptr[0]:%d\n*ptr:\t%d\nptr[0]:\t%d\n&ptr[0][0]:%d\n\n" ,ptr,&ptr[0],*ptr,ptr[0],&ptr[0][0]); // 使用陣列指標 int (*p)[3] = new int [4][3]; printf("陣列指標:\np:\t%d\n&p[0]:\t%d\n*p:\t%d\np[0]:\t%d\n&p[0][0]:%d\n\n" ,p,&p[0],*p,p[0],&p[0][0]); // 釋放記憶體 for(int i = 0; i < 4; ++i) { delete [] ptr[i]; //注意不要漏掉方括號 } delete []ptr; delete []p; delete []a; }
一維陣列:
a: 5284392
*a: -842150451
&a[0]: 5284392
指標陣列一步步申請:
ptr: 5284520
&ptr[0]:5284520
*ptr: 5284584
ptr[0]: 5284584
&ptr[0][0]:5284584
陣列指標:
p: 5284808
&p[0]: 5284808
*p: 5284808
p[0]: 5284808
&p[0][0]:5284808
請按任意鍵繼續. . .
對於方法一:ptr==&ptr[0],二者皆是指標陣列的第一個元素的地址,而*ptr與ptr[0]則是指標所指向的整型陣列空間的第一個元素的地址,即&ptr[0][0]。
對於方法二:我們可以看出,所有的變數都是一樣的,說明該方法在物理空間上不存在多個新開闢的記憶體,只是一次性地申請了row*col大小的空間。即為什麼使用陣列指標動態申請二維陣列在釋放空間時的寫法有多種。
在C++中,對於兩種方法,在釋放空間時,delete [] p表示釋放指標p所指向的物件,務必要記得寫“[]”,才能表示釋放的是陣列中的每一個元素,如果是物件,則會呼叫解構函式。
在C語言中的free(p)就沒有那麼多“麻煩”了,無論是單個內建型別還是陣列,free()函式的引數只要求傳入指標即可(不過C中沒有類與物件的例項與析構了),為什麼會這樣?這就是malloc的機制問題,malloc不關心申請的空間是什麼型別,只關心開闢的位元組數,這樣一來free只需知道指標便能正確地釋放記憶體。
說到這裡,順便小記一下new/delete和malloc/free的區別
- new/delete是C++中的運算子,可以過載;malloc/free則是標準庫函式
- 如果是非內建物件型別,new/delete在執行時會相應地呼叫建構函式和解構函式; malloc/free則不會。
- 使用方法上的區別,如上面劃橫線的部分分析。