在堆區申請二維數組的方法


問題引入

  在做題的時候需要在堆區申請一個二維數組。所以當時很自然用這種方式來申請: int *a = new int[row][col]; ,編譯器會報錯。

  首先,有個錯誤是我把二維數組名理解成一個一級指針。這是因為之前打印輸出二維數組名的地址時,二維數組名就是一個指向二維數組第一個元素地址的指針,所以錯誤地把二維數組名理解成是一個一級指針。

  然后,有人會說,用二級指針啊: int **a = new int[row][col]; ,編譯器同樣會報錯。不可以把二維數組名理解為一個二級指針。

 

二維數組名究竟是什么

  先說結論,如果有二維數組int a[row][col]二維數組名a其實是一個指向int[col]這一數據類型的指針而a這個變量的類型是int(*)[col]。這里的int[col],是指數據類型為int[col]的一維數組,換句話說,這個一維數組的每一個元素都是int[col]型

  所以,我們可以嘗試用這種方式來申請一個二維數組: int row = 10, col = 10; int (*a)[col] = new int[row][col]; ,這看上去沒有什么問題,正如我們上面所說的,如果用new來申請一個二維數組,那么會返回一個int(*)[col]類型的指針,同時我們用int (*a)[col]來接收返回的地址(這也意味着a是一個指針,指向int[col]這種數據類型),可是編譯器會有如下報錯:

[Error] array size in new-expression must be constant
[Error] the value of 'col' is not usable in a constant expression
[Note] 'int col' is not const

  編譯器說,col沒有用const修飾,所以無法確定數組大小,從而無法申請這個二維數組。也就是說,要在堆區創建一個二維數組二維數組的第一維必須是一個常量

  這是因為,在C++中並不存在所謂的“二維數組”,所謂的二維數組,或者是多維數組實際上都是一維數組組成的。對於二維數組a[row][col]來說它的每一個元素的數據類型實際上是一種一維數組也就是int[col]。而col的值不同,與之對應的int[col]這種類型也會不同,編譯器要確定的col值才可以確認int[col]到底是什么類型。比如int[3][4],和int[3][5],前者的每一個元素的數據類型是int[4],后者的每一個元素的數據類型是int[5],而且int[4]int[5]是兩種不同的數據類型

  所以,對於col這個普通變量, int (*a)[col] = new int[row][col]; 這種方式並不可以申請一個二維數組,因為編譯器無法確定int[col]是什么類型的。

  所以要用這種方式來申請二維數組,必須要讓編譯器知道int[col]是什么類型的,也就是說col必須是一個常量。這兩種方法都是對的: int row = 10; const int col = 10; int (*a)[col] = new int[row][col]; , int row = 10; int (*a)[10] = new int[row][10]; ,編譯器可以確認這個二維數組每一個元素的數據類型都是int[10]。

  至於為什么在棧區int a[row][col]; 可以申請二維數組,而在堆區不可以用這種方式來申請二維數組,我還不知道,如果你知道歡迎在評論區留言。

 

在堆區申請二維數組的方法

  其實上面已經知道了一種方法,那就是確認col的大小來申請二維數組,但這種方法的局限性很大。

  還可以通過二級指針來申請二維數組。

 1 #include <cstdio>
 2 
 3 int main() {
 4     int row = 5, col = 5;
 5     
 6     int **a = new int*[row];        // 先申請一個指針數組 
 7     for (int i = 0; i < row; i++) {
 8         a[i] = new int[col];        // 再申請row個大小為col的一維數組 
 9     }
10     
11     for (int i = 0; i < row; i++) {
12         for (int j = 0; j < col; j++) {
13             a[i][j] = 1;
14             printf("%d  ", a[i][j]);
15         }
16         putchar('\n');
17     }
18     
19     for (int i = 0; i < row; i++) {
20         delete[] a[i];              // 先釋放掉一維數組 
21     }
22     delete[] a;                     // 再釋放掉指針數組 
23     
24     return 0;
25 }

  運行結果如下:

   a[i][j]這種表述看上去是不是很像一個二維數組?其實它是有迷惑性的。按照上面申請內存的過程,實際上我們申請的這個“二維數組”的內存應該是這樣子的:

   只不過我們取元素所用的方法與二維數組的很像,但實際上這個二級指針所表示的二維數組的內存分配與在棧區創建的二維數組的內存分配(一塊連續的內存)是完全不同的。

  還有一種方法,是通過malloc函數來申請的。

 1 #include <cstdio>
 2 #include <cstdlib> 
 3 
 4 int main() {
 5     int row = 5, col = 5;
 6     
 7     int (*a)[col] = (int(*)[col])malloc(sizeof(int) * row * col);
 8     
 9     for (int i = 0; i < row; i++) {
10         for (int j = 0; j < col; j++) {
11             a[i][j] = 10;
12             printf("%d  ", a[i][j]);
13         }
14         putchar('\n');
15     }
16     
17     return 0;
18 }

  這里molloc函數返回的是int*型,我們需要把它強制類型轉換為int(*)[col]型,並且讓指向int[col]型的指針來接收,這種方式申請的二維數組的內存分配和在棧區創建的相同,都是一塊連續的內存。

 

參考資料

  C++用new創建二維數組的方法:https://blog.csdn.net/samuelcoulee/article/details/8674388

  用malloc動態申請一個二維數組的三種方法:https://blog.csdn.net/fengxinlinux/article/details/51541003


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM