C语言与java语言中关于二维数组的区别
作者:triumph_421
数组是编程语言中常用的数据结构,然而在不同的环境下,其定义及初始化的方式也不尽相同。下面来讲述一下C和Java中对于二维数组定义的区别以及其背后的原理。
在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中的二维数组是要先确立行数,进而才能确立列数,也就是要申请一片内存空间用来存放每个一位数组的地址,然后才能为每个一维数组分配内存空间。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。