首頁 > 軟體

C語言與java語言中關於二維陣列的區別

2022-08-19 14:02:59

陣列是程式語言中常用的資料結構,然而在不同的環境下,其定義及初始化的方式也不盡相同。下面來講述一下CJava中對於二維陣列定義的區別以及其背後的原理。

C語言中,二維陣列的初始化可以省略行數,但不能省略列數;而在java中卻是正好相反的,即列數可以省略,而行數是不能省略的。為什麼會是這樣呢?首先我們來回顧一下C和Java中二維陣列的定義。

C語言數中二維陣列的定義格式

型別名   陣列名 [行數][列數];

例如:

int a[3][2];        /*表示定義了二維陣列a,3行2列,6個元素 */

可見,在C語言中,二維陣列的元素數量等於行數和列數的乘積,所以二維陣列一經定義,其被分配的記憶體大小就已經確定了。

因此,對於單純的定義二維陣列來說,其行和列都是不可省略的,一旦有省略,那麼在編譯時就會報“陣列記憶體大小不確定”的錯誤。

程式碼段及編譯結果如下圖所示:

int a[][5];        /*在定義陣列a時省略了行數*/ 

而我們所說的可以省略行數,是在對二維陣列初始化的時候,即在定義時給陣列元素賦初值的時候。要想編譯時不報錯,就需要讓編譯器知道該陣列佔用的記憶體空間,只不過在有省略的情況下就只能讓編譯器自己推斷出陣列佔用的記憶體空間了,那麼為什麼省略了行就能夠推斷出來,而省略了列就不可以呢?

這就要提到二維陣列元素在記憶體中的儲存方式了。C語言是按照“先行後列”的順序來儲存陣列的,即先儲存第0行的元素,然後是第1行的元素,以此類推。所以編譯器必須知道每行元素的個數,才能由初始化的結果推斷出行數,進而推斷出二維陣列所佔用的記憶體空間。而每行元素的個數正是二維陣列的列標。

Java語言中二維陣列的定義與初始化

Java語言中對於二維陣列的定義稍微有些複雜,建立一個Java陣列需要三個步驟:宣告陣列、建立陣列空間、建立陣列元素並初始化。

其中初始化可以分為:靜態初始化和動態初始化。

靜態初始化

int[][] arr = new int[][]{{1,2,3,6},{4,5},{7,8,9}};
等價於
int arr[][] = {{1,2,3,6},{4,5},{7,8,9}};

動態初始化

int [][] arr3 = new int[4][3];
int [][] arr4 = new int[4][];

由動態初始化可以看出,在還沒有為二維陣列元素賦初值時,列下標是可以省略的。在這裡要宣告的一點是:C語言中二維陣列的每個元素都是大小相同的一維陣列,即如果把其中的各個元素鋪開,會是一個矩形;但在Java中並不要求每一個一維陣列的大小一致,所以也就不能在定義的時候說明列數。

下面給出兩者的對比截圖

(以相同的元素分別為C和Java中的二維陣列初始化)

C語言中的陣列元素分佈

int arr[3][4] = {{1,2,3,6},{4,5},{7,8,9}};
for(int i = 0; i < 3; i++){
    for(int j = 0; j < 4; j++){
        printf("%d  ",arr[i][j]);
	}
		printf("n");
	} 

Java中的陣列元素分佈

int[][] arr = new int[][]{{1,2,3,6},{4,5},{7,8,9}};
		for(int i = 0; i < arr.length; i++){
			for(int j = 0; j < arr[i].length; j++){
				System.out.print(arr[i][j] + " ");
			}
			    System.out.println();
		}

那麼Java的二維陣列是怎樣儲存的呢?

Java二維陣列的陣列名儲存在棧中,堆裡面存放的是new出來的結構,比如具體的陣列元素。在定義二維陣列時,先在棧裡申請行數,然後等具體要用到哪一個一維陣列了再向堆申請記憶體。

所以在定義二維陣列時,若省略了列數,則可以看做是申請了若干個(行數)一維陣列,但是具體的一維陣列中的資料暫時是不知道的。

下面給出Java中二維陣列的記憶體解析圖:

由上圖可知:陣列arr1在定義時行標和列標都給出了,其定義的過程可以描述為:先在棧裡為arr1申請行數,即為arr1申請一片空間並把空間的首地址賦給arr1,相當於確定好了該二維陣列arr1中有三個元素,分別為三個一維陣列。而列標被定義出來就意味著為二維陣列的每個資料元素都分配好了記憶體空間,並把三個一維陣列的首地址傳了過去。對於arr1的各個資料元素,因為在定義的時候沒有賦初值,且是String型別,所以預設為null。

陣列arr2在定義時省略了列標,所以相當於只給出了arr2這個int型二維陣列的四個一維陣列元素,而沒有為這四個一維陣列賦初值。而因為arr2的四個元素都為參照資料型別(陣列),所以預設值為null。

  • arr2[1] = new int[5]; 相當於為arr2的第二個元素指明瞭一塊記憶體空間,並把這塊空間的首地址賦給了arr2[1],arr2[1]的長度為5,元素型別為int型,又因為沒有為這個一維陣列賦初值,所以預設值為0。
  • arr2[1][1] = 1; 的作用是把arr2[1]這個一維陣列的第二個元素賦值為1。
  • arr2[2][2] = 1; 因為沒有為arr2的第三個元素分配記憶體空間,所以此時會報空指標異常。

最後,再次回到Java中定義二維陣列時為什麼不能省略行數的問題。結合上述的記憶體解析,我們知道Java中的二維陣列是要先確立行數,進而才能確立列數,也就是要申請一片記憶體空間用來存放每個一位陣列的地址,然後才能為每個一維陣列分配記憶體空間。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com