C语言与java语言中关于二维数组的区别

 更新时间:2022年08月19日 11:21:37   作者:triumph_421  
这篇文章主要介绍了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中的二维数组是要先确立行数,进而才能确立列数,也就是要申请一片内存空间用来存放每个一位数组的地址,然后才能为每个一维数组分配内存空间。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • floyd算法实现思路及实例代码

    floyd算法实现思路及实例代码

    这篇文章主要介绍了floyd算法实现思路及实例代码,有需要的朋友可以参考一下
    2014-01-01
  • 详解Bucket Sort桶排序算法及C++代码实现示例

    详解Bucket Sort桶排序算法及C++代码实现示例

    桶排序是一种线性排序算法,这里我们来详解Bucket Sort桶排序算法及C++代码实现示例,需要的朋友可以参考下
    2016-07-07
  • C++中sprintf()函数的使用详解

    C++中sprintf()函数的使用详解

    本篇文章是对C++中sprintf()函数的使用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++ 栈和队列的实现超详细解析

    C++ 栈和队列的实现超详细解析

    栈和队列,严格意义上来说,也属于线性表,因为它们也都用于存储逻辑关系为 "一对一" 的数据,但由于它们比较特殊,因此将其单独作为一章,做重点讲解
    2022-03-03
  • 用C++实现SLR语法分析程序

    用C++实现SLR语法分析程序

    大家好,本篇文章主要讲的是用C++实现SLR语法分析程序,感兴趣的同学赶紧来看一看吧,对你有帮助的话记得收藏一下
    2022-02-02
  • 在C++中使用HP-Socket

    在C++中使用HP-Socket

    这篇文章主要介绍了C++中简单使用HP-Socket,HP-Socket 是一套通用的高性能 TCP/UDP /HTTP 通信 框架 ,包含服务端组件、客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP /HTTP 通信系统,下面来看看更具体的介绍吧
    2021-11-11
  • C语言基于回溯算法解决八皇后问题的方法

    C语言基于回溯算法解决八皇后问题的方法

    这篇文章主要介绍了C语言基于回溯算法解决八皇后问题的方法,简单描述了八皇后问题,并结合实例形式分析了C语言使用回溯算法解决八皇后问题的相关操作技巧,需要的朋友可以参考下
    2018-06-06
  • C++使用适配器模式模拟实现栈和队列

    C++使用适配器模式模拟实现栈和队列

    不论是C语言还是C++,我们都用其对应的传统写法对栈和队列进行了模拟实现,现在我们要用新的方法模拟实现栈和队列,这个新方法就是适配器模式,文章通过代码示例和图文介绍的非常详细,需要的朋友可以参考下
    2024-12-12
  • 获取C++变量类型的简单方法

    获取C++变量类型的简单方法

    这篇文章主要介绍了获取C++变量类型的简单方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • C语言冒泡排序超全面实现流程

    C语言冒泡排序超全面实现流程

    算法中排序是十分重要的,而每一个学习计算机的都会在初期的时候接触到这种排序,下面这篇文章主要给大家介绍了关于c语言冒泡排序的相关资料,需要的朋友可以参考下
    2023-01-01

最新评论