二维数组
当数组元素具有两个下标时, 该数组称为二维数组。 二维谁可以看做具有行和列的平面数据结构。
如何使用二维数组
二维数组定义的一般形式为:
类型说明符 数组名[常量表达式1][常量表达式2]
其中常量表达式1表示第一维下标的长度,常量表达式2 表示第二维下标的长度。
其命名规则与一维数组的命名规则相同。比如:
int a[3][4] ;
第一行表示定义了一个 3×4,即 3 行 4 列总共有 12 个元素的数组 a。这 12 个元素的名字依次是:a[0][0]、a[0][1]、a[0][2]、a[0][3];a[1][0]、a[1][1]、a[1][2]、a[1][3];a[2][0]、a[2][1]、a[2][2]、a[2][3];
与一维数组相同,二维数组的行序号和列序号的下标都是从 0 开始的。元素 a[i][j] 表示第 i+1 行、第 j+1 列的元素。数组 int a[m][n] 最大范围处的元素是 a[m–1][n–1]。所以我们在日常引用数组元素时应该注意,下标值应在定义的数组大小的范围内。
在C语言中,二维数组进行存放时,是按行进行存放的,就例如上文中的数组a,就是先存放a[0]行,再存放a[1]行、a[2]行,并且每行有四个元素,也是从0-3依次存放的。
对于二维数组而言,其只是在概念上是二维的:其下标在两个方向上变化,所以对其访问一般需要两个下标。
实际上在内存中并不存在二维数组,二维数组实际的硬件存储器是连续编址的,也就是说内存中只有一维数组,在放完一行元素之后顺次放入第二行元素,与一维数组的存放方式相同其内存地址依旧是连续的。
下面我们来看下这串代码:
要求,创建一个3×4的数组,并按照数组存放方式去从1开始依次递增赋值。
#include <stdio.h> int main() { int a[3][4]; //定义二维数组 /* 这个二维数组由三个一维数组组成 这三个一维数组的数组名分别是 a[0],a[1],a[2] 而这个一维数组是 int [4] */ int i = 0; int j = 0; int num = 0; for (i = 0; i < 3; i++) //for循环给数组每个元素赋值 { for (j = 0; j < 4; j++) { a[i][j] = num++; } } for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { printf("%d ", a[i][j]) ; //输出每个成员的值 } printf("\n"); } return 0; }
运行结果:
二维数组的初始化
二维数组初始化的形式为:
数据类型 数组名[常量表达式1][常量表达式2] = { 初始化数据 } ;
我们可以用下面的方法对二维数组进行初始化。
1)按行进行初始化
在 { } 内部再按照行数用 {}二次进行分开去初始化数组。其中行与行之间的{}要用逗号隔开;代码中{1,2,3,4}为第一行数组初始化;{5,6,7,8}为第二行数组初始化;{9,10,11,12}为第三行数组初始化。
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
2)连续赋值初始化
连续赋值就是将 { } 中的数据依次赋值给数组中的各元素。其赋值顺序与二维数组存放顺序是相同的。就比如a[3][4]数组初始化,先从a[0]行a[0][0]元素开始到a[0][3]元素之后再到a[1]行a[1][0]元素开始.......最终到a[2][3]为止。
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
3)部分元素初始化
我们在对二维数组进行赋值的时候可以只给数组中部分元素赋初值,那么未初始化的元素则为0。
int a[3][4] = { 1, 2, 3, 4 } ; int a[3][4] = {{1, 2}, {5}, {9}};
第一行是只对二维数组的第一行进行初始化,其余行则为0。
第二行是对第一行的前两个元素赋值、第二行和第三行的第一个元素赋值。其余元素自动为 0。
上面两种情况初始化后的结果分别是:
4)全员赋0初始化
二维数组“清零”,也就是将里面每一个元素都赋值为零,这时就不需要跟之前一样将每个元素都赋值一遍了。
int a[3][4]={0};
5)第一维不定义初始化
如果我们在定义的时候对所有的元素都赋初值的话,那么我们可以不指定第一维的长度,但第二维的长度不能省。这时系统会根据数据总数和第二维的长度算出第一维的长度。但这种省略的写法几乎不用,因为可读性差。
int a[][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
所以二维数组的初始化方式总结下来也就以下几种了:
/
/按行进行初始化 int a[3][4] = {{ 1, 2, 3, 4 },{ 5, 6, 7, 8, },{ 9, 10, 11, 12 }} ; //连续赋值初始化 int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12 } ; //部分元素初始化 int a[3][4] = { 1, 2, 3, 4 } ; //全员赋0初始化 int a[3][4] = {0} ; //第一维不定义初始化 int a[][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
数组名
和一维数组一样,数组名是一个地址的常量,代表数组中首元素的地址。
#include <stdio.h> int main() { //定义了一个二维数组 int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12 } ; //数组名为数组首元素地址,二维数组的第0个元素为一维数组 printf("a = %p\n", a) ; //输出地址 printf("a[0] = %p\n", a[0]) ; //测二维数组所占内存空间 //sizeof(a) = 3 * 4 * 4 = 48 printf("sizeof(a) = %d\n", sizeof(a)) ; //测第0个元素所占内存空间 printf("sizeof(a[0]) = %d\n", sizeof(a[0]) ) ; //测第0行0列元素所占内存空间 printf("sizeof(a[0][0]) = %d\n", sizeof(a[0][0])) ; return 0; }
运行结果:
通过运行结果我们可以看出,数组名a的地址也就是二维数组中a[0][0]的地址。以及每个int元素所占内存是4,如果要测量每行所占内存只需输入一个下标即可。
于是我们就可以用内存大小的比值去计算出二维数组行数和列数。具体计算操作如下:
//求二维数组行数 printf("i = %d\n", sizeof(a) / sizeof(a[0])) ; // 求二维数组列数 printf("j = %d\n", sizeof(a[0]) / sizeof(a[0][0])) ; //求二维数组行*列总数 printf("n = %d\n", sizeof(a) / sizeof(a[0][0])) ;
二维字符数组
二维字符数组是用来存放字符串, 二维字符数组每一行可以看做一维字符数组, 即二维字符数组的每一行可以存放一个字符串。
二维字符数组的定义
二维字符数组的定义与一般二维数组的定义方式相同,只是要使用char数据类型去进行定义。
char 数组名[第一维大小][第二维大小];
例如:
char a[3][4] ;
二维字符数组 a 有3行4列, 每一行可以存放长度小于或等于3的字符串(原因:不要忘记要给字符串结束标识符留一个位置)。
二维字符数组的初始化
其与二维数组的初始化方式大致相同,其也可以在定义时初始化。通常情况下,二维数组的每一行分别使用一个字符串进行初始化。
char a[2][6] = {"Hello","C++" } ; char a[][6] = {"Hello","C++"} ;//第二维同样不可省略 //等价于 char a[2][6] = {{"Hello"},{"C++"} } ;
以上三条初始化语句中以及等价关系中,二维数组的第一维大小均可省略。数组 a 的逻辑结构如下所示:
a由于在二维字符数组每个字符串单独占一行, 所以可以用 a[n] 引用该二维数组字符中第 n 行的字符串;也可以用 a[i][j] 引用某行某列中的单独一个字符串 。
二维字符教组的引用
在平时使用中,可以使用行下标和列下标引用二维字符数组中的每个元素(字符),例如:
printf ("%c",a[1][4]) ; //输出1行4列元素 scanf ("%c",&a[2][3]) ; //输入一个字符到2行3列元素中 a[2][0]='B' ; //把字符赋值给2行0列元素 printf ("%s",a[1]) ; //c[1]为第2行的数组名(首元素地址) scanf ("%s",a[2]) ; //输入字符串到c[2]行,从c[2]行的首地址开始存放
下面这些是我们在使用时经常与遇见的错误,这里我给大家列出来了几条:
a[0][0]="A" ; //行、列下标表示的为字符型元素,不能使用字符串赋值 printf ("%c",a[2]) ; //a[2]为第3行的首地址,不是字符元素,故不能用%c
多维数组
多维数组我们平时见到的其实并不多,所以在这里并不做强制要求,如果感兴趣的朋友可以了解一下。
多维数组的定义与二维数组类似,其语法格式具体如下:
数组类型修饰符 数组名 [n1][n2]…[nn]; int a[3][4][5] ; //定义三维数组 int b[4][6][7][3] ; //定义四维数组
这里我们拿三维数组来进行举例讲解:
其数组的名字是a,数组的长度为3,每个数组的元素又是一个二维数组,这个二维数组的长度是4,并且这个二维数组中的每个元素又是一个一维数组,这个一维数组的长度是5,元素类型是int。
#include <stdio.h> int main() { //定义三维数组 int a[3][4][5] = { { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 0 }, { 0 } }, { { 0 }, { 0 }, { 0 }, { 0 } }, { { 0 }, { 0 }, { 0 }, { 0 } } }; int i, j, k; for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 5; k++) { printf("%d, ", a[i][j][k]); //输出 } printf("\n"); } } return 0; }
结尾
好啦!到这里数组的基本知识也所剩无几了,如果还有什么不理解的地方可以在下方评论区随便留言,我看到后会及时的回复,当然只学这些数组知识是仅仅不够的,接下来我会出一期数组的实战强训练用于加强对本篇数组知识的学习以及强化一些深度知识,在那里就没有太多的知识点了,我会将一些数组中常见的题目(逆序,排序等),