1. 程式人生 > 其它 >c++在堆區中建立陣列的一些注意事項

c++在堆區中建立陣列的一些注意事項

技術標籤: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,可以給我們寫程式減少麻煩,尤其是寫大型程式的時候。