c++在堆區中建立陣列的一些注意事項
Q1:我們為什麼好端端的不在棧中建立陣列,偏要跑到堆區中哪?
R1:棧中的空間是有限的,在面對一些長度很大的陣列的時候,會有力不從心的感覺,所以我們選擇了在堆區中。
1.寫法
1.1堆區建立一維陣列的寫法
型別名 * 指標名=new 型別名[陣列長度]
eg: int *p=new int[10]
這就表示我們在堆區中建立了個int型別的一維陣列,長度是10,並且用int型別的指標指向他來便於我們後期維護。
注意:前後型別最好一致,或者可以轉換。如果前面是string,後面是int這顯然不行。
1.2堆區建立二維陣列的寫法
建立方法一:總感覺這個方法是在為了建立而建立,使用起來並不方便,也可能是我還沒找到正確的開啟方式。
型別名 (*指標名)[列數]=new 型別名[行數][列數]
eg:int (*p)[5]=new int[10][5]; 這就表示我們在堆區建立了一個十行五列的int型別陣列,但是這裡僅僅是定義了,還沒有賦值,不能直接用。
注意:1.括號很重要,千萬別忘了,很容易錯寫成int *p[10]=new int[10][5]; 這兩個意思是完全不同的,下邊這個連編譯都通不過,毫無邏輯可言。
2.這兩個位置的數字必須相同。
建立方法二:new/delete
int **Array = new int *[ArrayRow];
for (int i = 0; i < ArrayRow; i++){
Array[i] = new int[ArrayCol](); // 初始化 0
}for(i = 0; i < ArrayRow; i++) // 釋放記憶體
{
delete[] Array[i];
}
delete[] Array;
建立方法三:
malloc/free:
int **Array = (int**)malloc(ArrayRow * sizeof(int *)); // 先行
for (int i = 0; i < ArrayRow; i++)
{
Array[i] = (int*)malloc(ArrayCol * sizeof(int)); // 後列memset(Array[i], 0, ArrayCol * sizeof(int)); // 初始化 0
}for (int i = 0; i < 3; i++) // 釋放記憶體
{
free(Array[i]);
}
free(Array);
2.用法
2.1一維的用法
1.for迴圈賦值
//把指標設定為const型別,防止p後面被改變,這點很重要,之後在下面會特別介紹,防止指標中途改變從而導致最後無法被析構
int *const p=new int[10];
//為一維陣列賦值
for(int i=0;i<10;i++){
p[i]=i+1;
}
//呼叫一維陣列
for(int i=0;i<10;i++){
cout<<p[i]<<endl;
}
//用完記得刪除
delete[]p;
2.初始階段初始化
int* Array = new int[ArraySize]; // 僅在自由儲存區中申請記憶體,不初始化
int* Array = new int[ArraySize](); // 初始化陣列全為 0
int* Array = new int[5]{ 1,2,3,4,5 }; // 初始化陣列為 1,2,3,4,5
int* Array = new int[5]{ 1 }; // 初始化陣列為 1,0,0,0,0
delete[] Array; // 釋放記憶體
2.2二維的用法
C++又規定了陣列名代表陣列首元素地址,因此array[0]代表一維陣列array[0]中第0行第0列元素的地址,即&array[0][0],array[1]的值是&array[1][0],array[2]的值是&array[2][0]。
#include<iostream>//預處理
using namespace std;//名稱空間
int main()//主函式
{
//堆區申請記憶體,建立一個二維陣列併為其初始化值。
int(*p)[4]=new int[3][4] { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
int i, j;//定義代表行數和列數的整型變數
cout << "輸入行號列號:";//提示語句
cin >> i >> j;//鍵盤輸入行數和列數
cout << *(*(p + i) + j) << endl;//偏移量計算訪問法
cout << p[i][j] << endl;//不妨稱之為幾何訪問法,
return 0;
}
3.為什麼要把指標設定為const?
原回答網址:
https://blog.csdn.net/charlessimonyi/article/details/8277616
常見的通過偏移量來訪問的兩種方式:
*(pa+2)=15;
pa[2]=15;
下面問題來了:
pa++;
*(pa)=10
這樣看上去,對pa指標自加後pa指標指向了陣列的第二個元素,然後對第二個元素賦值為10,編譯沒有錯,也能成功賦值。
但要注意!我們在堆中建立的東西用完後需要用delete來釋放,對於堆中陣列,這樣來釋放:
delete [] pa;
由於我們剛才對pa進行了自加,這裡用delete釋放的時候就會出錯,因為pa自加後就沒有指向陣列第一個元素的地址了,系統無法正確的釋放我們在堆中建立的陣列所佔的記憶體空間。就會出現卡死等異常情況。所以千萬不要改變pa指標。
為了防止對pa指標的誤操作,最好的辦法是將它申明為常指標,我們在一開始堆中建立陣列的時候就這樣:
int *const pa = new int[10];
將pa申明為常指標後,我們就無法改變pa指標了,比如無法pa++;無法pa+=2;但是我們仍然可以正常的訪問和修改pa指向的陣列元素的值,pa[1]=10;
delete [] pa;
pa=NULL;
最後,在堆中建立的東西,用完後都要delete以免發生記憶體洩露。delete釋放後指標要及時指向NULL,防止野指標出現。
善用const,可以給我們寫程式減少麻煩,尤其是寫大型程式的時候。