C語言與java語言中關於二維數組的區別

數組是編程語言中常用的數據結構,然而在不同的環境下,其定義及初始化的方式也不盡相同。下面來講述一下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中的二維數組是要先確立行數,進而才能確立列數,也就是要申請一片內存空間用來存放每個一位數組的地址,然後才能為每個一維數組分配內存空間。

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: