大家好,很高兴又和大家见面啦!在上一篇我们介绍了一维数组的相关内容,今天咱们要介绍的是二维数组的相关内容。
二维数组的创建和初始化
1.二维数组的创建
(1)什么是二维数组
个人理解
对于二维数组,我是这样理解的:
一维就是一条线,二维就是一个面,那一维数组就是只有一行或者一列的数组,而二维数组则是拥有行和列的数组。
(2)二维数组如何创建
既然我们理解的二维数组具有行和列,那我们就需要有两个下标来进行表示,如:
//二维数组的创建
char a[1][2];
short b[1][2];
int c[1][2];
和一维数组的创建方式一样,有数组元素类型、数组名、以及数组的大小,但是这里的大小由两部分组成,这里我们理解的是行与列两部分,具体是不是呢?我们接着往下看;
2.二维数组的初始化
(1)初始化的分类
和一维数组一样,二维数组同样也是分为两种初始化:完全初始化和不完全初始化。
完全初识化
数组初始化的元素个数与数组大小相同;
不完全初始化
数组初始化的元素个数小于数组大小,未被初始化的元素默认为0;
(2)二维数组初始化
在一维数组中,我们知道了初始化就是在创建数组时给数组的内容一些合理初识值,那二维数组又应该怎样赋值呢?我们通过代码来说明二维数组的初识化:
在代码中我们先定义了一个二行三列的二维数组,随即就给它赋值了4个元素,从调试中我们可以看到,各个元素的下标分别是
a[0][0]、a[0][1]、a[0][2]、a[1][0]、a[1][1]、a[1][2]
有没有一种熟悉感,是不是和线性代数学的行列式很相似啊,既然这样那我们是不是可以把这个数组的元素用图像表示出来呢?
这里我们可以总结一下几点内容:
- 二维数组的下标也是从0开始,二维数组的首元素下标为[0][0],然后从第二个下标开始依次增加;
- 二维数组的元素个数为两下标的乘积,如
a[2][3]
这个二维数组的元素个数有2*3=6
个; - 二维数组在初始化时,和一维数组一样会从首元素开始初始化,未被初始化的元素,会默认被0初始化。
那我能不能把1、2赋值给第一行的两个元素,把3、4赋值给第二行的两个元素呢?答案是可以的。如图所示:
这里我是这么理解的,既然二维数组分行和列的话,通过元素的下标我们可以将行相同的元素看做一个整体,或者说看做一个一维数组也就是a0[3]
和a1[3]
两个数组,那我的二维数组我就可以写成a[2][3]={a0[3],a1[3]}
,现在我们再来给这个数组初始化的话是不是就相当于分别给a0[3]
和a1[3]
这两个数组初始化呢,所以我们只需要把需要赋给它们的初始值用大括号括起来就OK了。
接下来有朋友可能就会提问了,在一维数组中我们有提到过一个变长数组的概念,也就是在创建数组时,不给定数组大小,只给定数组初始化的元素,我们可以通过元素的增加或减少来改变数组的大小,如a[]={1,2,3,4,5,6}
。那在二维数组中有没有这种概念呢?下面我们来测试一下,分别从省略行和列、省略行、省略列来进行探讨:
在省略行和列时,系统会报错说明a缺少下标,并在第二个中括号下面标注了一下;
我们在省略行时,代码成功编译,并且根据列的大小将元素划分成了两组;
我们在省略列时,系统再次报错,这一次报错了两个内容,一个缺少下标,一个初始值设定项值太多,并在代码的第二个中括号和元素的第四个元素下做了标注。
从上面的结果,我们可以得出以下结论:
- 二维数组在创建时,可以不用确定第一个值的大小,但是第二个值的大小必须确定;
- 在省略第一个值时,数组元素会根据第二个值的大小将元素进行分组。
二维数组的初始化,我相信各位朋友都了解了,接下来我们来看一下二维数组是如何使用的;
3.二维数组的使用
(1)通过下标访问元素
在一维数组中,我们尝试过通过下标来访问各个元素,并将元素打印出来,那在二维数组中又可以不可以呢?下面我们来尝试一下:
//通过下标访问二维数组的元素
int main()
{
int a[3][4] = { {1,2,3},{4,5,6},{7,8,9,10} };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
return 0;
}
从结果我们可以看到,在二维数组中我们依旧可以通过下标来访问数组的各个元素;
(2)通过下标来计算数组大小
和一维数组一样,我们也来借助sizeof来计算数组大小:
int sz = sizeof(a) / sizeof(a[0][0]);
printf("\n%d\n", sz);
从结果我们可以看到,二维数组同样也能够通过下标来计算二维数组的大小;
(3)通过第二个值计算第一个值
在前面我们也提到了,我们在初始化数组时,可以省略第一个值,但是不能省略第二个值,而且通过两个下标的乘积我们可以确定数组的大小,那我在省略第一个值的情况下,我能不能通过下标来计算第一个值呢?
//为数组第一个值定义变量
int x = 0;
//根据x*4=sz可得
x = sz / 4;
printf("第一个值为%d\n", x);
这里我们可以看到,我们可以通过第二个值来计算第一个值。既然已经知道了二维数组时如何使用的了,那我们再来探讨一下,二维数组在内存中又是如何存储的;
4.二维数组在内存中的存储
(1)二维数组的存储
在一维数组中我们知道了数组在内存中通过地址进行存储,地址又通过十六进制的形式被打印出来,在一维数组中,数组中的元素是由低地址到高地址连续存放的,那在二维数组中,又会是怎样一个情况呢?我们通过代码来看一下:
//通过下标访问二维数组的元素
int main()
{
int a[][4] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&a = %p\n", &a);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("&a[%d][%d] = %p\n", i, j, &a[i][j]);
}
}
return 0;
}
从打印的结果中我们可以看到,整型二维数组a的地址与首元素的地址相同,而且每个元素的地址都是相差4个字节,从这里我们可以得出以下结论:
- 二维数组与一维数组一样,数组的地址与首元素的地址相同;
- 各元素之间地址相差大小与元素的类型所占空间大小相同;
- 在二维数组中,元素也是按由低地址到高地址连续存放的;
(2)重新理解二维数组
从这个结论中我们对二维数组的理解要稍微变化一下了,前面我们对二维数组的理解是二维数组是由行和列组成的,我们对二维数组的创建是:
//二维数组的创建
type_t arr_name[row][arow]
type_t——数组元素类型
arr_name——数组名
row——行
arow——列
通过二维数组在内存中是连续存放的这个信息,那对二维数组的理解应该变成区域数量和区域大小会更加合适,也就是:
//二维数组的创建
type_t arr_name[zone_num][zone_size]
type_t——数组元素类型
arr_name——数组名
zone_num——区域数量
zone_size——区域大小
现在我们在回过头来理解二维数组的创建:
//二维数组的创建
char a[1][2];
//char——字符类型;
//a——数组名;
//1——有1个分区;
//2——分区大小为2,也就是每个分区里面有两个元素
short b[3][4];
//short——短整型类型;
//b——数组名;
//3——有3个分区;
//4——分区大小为4,也就是每个分区里面有4个元素
int c[5][6];
//int——整型类型;
//c——数组名;
//5——有5个分区;
//6——分区大小为6,也就是每个分区里面有6个元素
那现在就能解释为什么我们在初识化二维数组时第一个值可以省略,而第二个值不行了:
因为每个分区的大小不定的话数组的分区数量也无法确定,即使数组的分区数量确定了,没有分区大小也无法确定总的元素个数,但是每个分区的大小确定好了,我们就能根据总个数来计算分区的数量,所以我们可以得到:
我们在定义变长二维数组时,必须要确定每个分区的大小,分区的数量可以随着元素的增加而增加;
之所以第一个值与第二个值相乘等于二维数组的大小,现在我们也很好解释了:
分区的数量与每个区域的元素个数相乘得到的是元素的总个数,在数组中元素的总个数与数组的大小相等所以我们可以得到:
二维数组的大小=分区的个数*一个区域的大小
5.二维数组知识点汇总
(1)二维数组的创建
二维数组是根据数组的区域个数与每个区域的大小来进行创建的,创建二维数组的结构如下:
//二维数组的创建
type_t arr_name[zone_num][zone_size]
type_t——数组元素类型
arr_name——数组名
zone_num——区域数量
zone_size——区域大小
(2)二维数组的初始化
在对二维数组进行初始化时,有两种方式:
直接初始化
直接初始化时,数组会根据区域大小依次将区域内的元素进行初始化,未被初始化的元素由0初始化,如:
//直接初始化
int a[2][3] = { 1,2,3,4 };
分区域初始化
分区域初始化时,我们需要用大括号将各区域分开,未被初始化的元素由0初始化,如:
//分区域初始化
int b[3][4] = { {1,2},{3,4} };
创建变长二维数组时,不能省略区域大小,也就是int a[][3]={1,2,3,4,5,6}
;此时二维数组满足:
区域数量会随着元素个数的改变而改变
(3)二维数组的使用
在二维数组中我们可以:
- 通过下标访问元素
- 通过下标计算元素大小
- 二维数组的大小=分区数量*区域大小
- 通过下标确定数组的分区数量
(4)二维数组在内存中的存储
二维数组在内存中的存储与一维数组相同:
- 二维数组在内存中是由低地址到高地址连续存放的;
- 地址之间相差大小就是元素类型所占空间的大小;
- 二维数组的地址与首元素的地址相同;