本文目录
引言
在C语言中,数组是一种非常重要的数据结构,它允许我们存储固定大小的同类型元素集合。通过使用数组,我们可以方便地处理大量数据,提高程序的效率和可读性。数组的类型分为一位数组和二维数组,还有多维数组,而今天小编将要给大家介绍的是二维数组的相关知识。一起来看看吧!!!
正文
一 二维数组的创建
知其然才能知其所以然,所以我们先来看看二维数组的概念。
1. 二维数组的概念
相信看过小编上篇关于一维数组的介绍的宝子们对索引一词并不会感到陌生,但这里的行索引和列索引又是什么,难道是说明二维数组有两个不同功能的下标?带着这个疑惑,接着往下看。
知道这个二维数组的概念后,我们再来学习二维数组的创建。
2. 二维数组的创建
- 而行索引就是用来访问二维数组的行数,列索引就是用来访问二维数组的列数。具体怎么访问?我们之后再讨论。
以下为例:
int arr[2][3];
double arr1[3][4];
这样我们就创建了两个二维数组。
而事实上,二维数组在创建时是可以省略行数的,但一定不能省略列数。为什么?
其实你仔细思考就可以想到:
- 所以我们在创建一个二维数组时不可省略列数,可以省略行数。
所以以下的二维数组的创建是正确的
1 int arr [][5] = { 1, 2, 3 };
2 int arr [][6] = { 1, 2, 3, 4, 5, 6, 7, 8 };
3 int arr [][7] = { {1, 2}, {3, 4}, {5, 6} };
而以下的二维数组的创建是错误的
1 int arr [5][] = { 1, 2, 3 };
2 int arr [6][] = { 1, 2, 3, 4, 5, 6, 7, 8 };
3 int arr [7][] = { {1, 2}, {3, 4}, {5, 6} };
- 好好利用这个知识点,可以在我们不知道我们将会创建多少个元素的二维数组但是知道
列数
时最大的节约内存空间,但也可能造成语法错误。所以一定要牢记:二维数组在创建时是可以省略行数的,**但一定不能省略列数**。
和一维数组一样,学完了二维数组的创建,我们来学二维数组的初始化。
二 二维数组的初始化
同样地,二维数组的初始化也分为不完全初始化和完全初始化,我们先来看看不完全初始化是怎样的。
1. 不完全初始化
以下为例:
#include<stdio.h>
int main(){
int arr[2][3] = { 1, 2, 3, 4, 5 };
return 0;
}
由上可知:
- 该二维数组的行数和列数分别为:【2】和【3】,所以我们不难得出该数组的数组元素的总数为
6
,而我们可以看到小编这里只对5
个元素进行了赋值,是哪5
个呢?
我们用监视窗口看一下:
由图可知:
arr[0][0],arr[0][1],arr[0][2],arr[1][0],arr[1][1]
被分别初始化为1,2,3,4,5
,只有arr[1][2]
没被赋值。所以我们不难看出:二维数组的初始化也是随着下标从小到大进行赋值的,只不过这里的下标有行下标和列下标,也就是行索引和列索引。并且似乎行索引对赋值顺序的决定作用更大。这里就先不深入讨论,后文会细讲。
看完了二维数组的部分初始化,我们再来学习二维数组的完全初始化。
2. 完全初始化
以下为例:
#include<stdio.h>
int main(){
int arr[2][3] = { 1, 2, 3, 4, 5, 6};
return 0;
}
这里同样用监视窗口看一下数组元素有没有被我们放进去初值:
不出所料,相信这对于聪明的宝子们还是很简单的。那就再接着往下看。
接下来的就是一维数组不具备的独特初始化方式:按照行初始化。那一起来看看吧!
3. 按照行初始化
是的,You are so good! ! !
那该怎么达到我们想要的赋值效果呢?
这就要使用{}
这个东东了。
以下为例:
#include<stdio.h>
int main(){
int arr[2][3] = { {1}, {2, 3}};
return 0;
}
如果没有使用{}
,此次的赋值结果由上可知应为arr[0][0] = 1,arr[0][1] = 2,arr[0][2] = 3,arr[1][0] = 0,arr[1][1] = 0,arr[1][2] = 0;
而使用了{}
的实际结果如图:
显然,这里的效果就是我们猜想的结果。
- 按行初始化可以使得我们给二维数组初始化时更加灵活。
三 二维数组的使用
当然,学习二维数组的使用毫无疑问从二维数组的下标开始学起。
1.二维数组的下标
假设我们有一个二维数组 arr[m][n]
,则:
m
表示数组的行数。n
表示数组的列数。
那么,数组中的某个元素可以通过 arr[i][j]
来访问,其中:
i
是元素的行下标,取值范围是 0 到 m-1。j
是元素的列下标,取值范围是 0 到 n-1。
例如,对于以下二维数组:
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
要访问第二行第三列的元素(即数字7),可以使用 arr[1][2]
。
2.使用场景
哈哈!宝子们是不是被吓了一跳,小编在刚看到时也被吓了一跳。是不是觉得有很多没听过的专业名词?没关系,小编在之后的日子里会带着大家把这些“拦路虎”一一征服!!!相信小编,也请相信自己!!!
在目前,我们需要掌握的就是二维数组的遍历。
如何遍历?这里小编就以最简单的例子按行打印二维数组为例抛砖引玉:
#include<stdio.h>
int main(){
int arr[2][3] = {1, 2, 3, 4, 5, 6};
int i = 0;
int j = 0;
for (i; i < 2; i++) {
for (j; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
虽然例子简单,但小编想让大家感受到的是:
- 一般我们在遍历二维数组时,都会使用两个整型变量
i
和j
并初始化为0。至于为什么初始化为0,这也是因为C语言的数组的下标从0开始; - 且一般会使用两个循环,以
for
循环最为常见进行遍历;
由于现在我们还处于初识二维数组的阶段,所以对二维数组的使用暂讲到这,大家理解完本文可以多去一些刷题网站 加深理解哦!
那现在就让我们进入本文的最后一章节—— 二维数组在内存中的存储
四 二维数组在内存中的存储
这里小编就先从二维数组在内存中的存储结构开始讲起哈。
1.存储结构
所以我们引申得到:arr[0]
是第一行数组元素的数组名。这很重要,在我们后面理解一维数组和二维数组的数组名有大用。
接着是内存布局
2.内存布局
这里小编也可以通过打印出一个二维数组的元素的所有地址验证上述说法:
#include<stdio.h>
int main(){
int arr[2][3] = {1, 2, 3, 4, 5, 6};
int i = 0;
int j = 0;
for (i; i < 2; i++) {
for (j; j < 3; j++) {
printf("%p\n", &arr[i][j]);
}
printf("\n");
}
return 0;
}
运行结果为:
注:
- 在64位机器(现在的大部分计算机)中地址的大小是8个字节;
- '%p’占位符打印的是十六进制表示下的地址;
- 两个十六进制位数字就占用一个字节
所以我们不难发现:整形数组的相邻数组元素首字节地址大小相差4个字节,也就是一个整型数据的大小。
所以我们可以得出:
- 二维数组的元素在内存中的存储是连续的,也就是紧挨着的。这和一维数组是一样的
再接着来看看二维数组的访问方式。
3.访问方式
例:
#include<stdio.h>
int main(){
int arr[2][3] = {1, 2, 3, 4, 5, 6};
int i = 0;
int j = 0;
arr[1][2] = 7;
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
运行结果为:
我们这就通过二维数组的下标(索引)访问并修改了特定的元素的值。
最后我们来看看二维数组的地址计算。
4.地址计算
假设这有一个二维数组arr[2][3];
,如果我们知道了首元素arr[0][0]
的地址,那其他的元素的地址就可以很好的算出。不妨假设&arr[0][0] = 0000000000000000
,则&arr[1][2] = 0000000000000018
。
为什么?这就需要宝子们自己思考啦!!!理解这题就掌握了这节知识——二维数组的内存布局和地址计算。
- 总的来说,C语言的二维数组在内存中是以连续的方式存储的,这使得它们非常适合于需要快速访问和修改大量数据的场景。