8.2.1 二维数组的用法
二维数组是多维数组中最简单的形式。
1.定义二维数组
二维数组的下标是两个,其定义格式如下。
类型说明符 数组名[常量表达式1][常量表达式2]
其中,“常量表达式1”表示第一维下标的长度,“常量表达式2”表示第二维下标的长度。例如:
int a[3][4];
上述代码定义了一个3行4列的整型数组,数组名为a,其下标变量的类型为整型。该数组的下标变量共有3×4个,具体如下。
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]
二维数组在概念上是二维的,即其下标是在两个方向上变化的,下标变量在数组中的位置处于一个平面之中,而不像一维数组只是一个向量。但是,实际的硬件存储器却是连续编址的,也就是说存储器单元是按一维线性排列的。在一维存储器中存放二维数组有两种方式:一种是按行排列,即排完一行之后顺次放入第2行,另一种是按列排列,即排完一列之后再顺次放入第2列。在C语言中,二维数组是按行排列的。也就是:先存放a[0]行,再存放a[1]行,最后存放a[2]行。每行中的4个元素也是依次存放的。由于数组a说明为整型,该类型占2字节的内存空间,所以每个元素均占用2字节的空间。
一个二维数组可以看作是若干个一维数组,例如上面的数组a[3][4]可以看作是3个长度为4的一维数组,这3个一维数组的名字分别是a[0]、a[1]和a[2]。
2.引用二维数组
在C语言中,二维数组的引用格式如下。
数组名[下标][下标]
其中,“下标”为整型常量或整型表达式。下面就引用了一个二维数组元素:
a[3][4]
下标和数组说明在形式上有些相似,但这二者具有完全不同的含义。数组说明的方括号中给出的是一维长度,即可取下标的最大值;而数组元素中的下标是该元素在数组中的位置标识。前者只能是常量,后者可以是常量、变量或表达式。
看下面的应用:
一个学习小组有5个人,每个人有3门课的考试成绩。求全组分科的平均成绩和各科总平均成绩。各成员的成绩如表8-1所示。
表8-1 成绩详情表

此时就可以使用二维数组来编程实现,首先设一个二维数组a[5][3]用于存放5个人3门课的成绩。然后设一个一维数组v[3]存放所求得的各分科平均成绩,设变量average为全组各科总平均成绩。具体实现代码如下。
int main(void){ int i, j, s=0, average, v[3], a[5][3]; printf("输入成绩\n"); for(i=0; i<3; i++){ for(j=0; j<5; j++) { scanf("%d", &a[j][i]); s=s+a[j][i]; } v[i]=s/5; s=0; } average =(v[0]+v[1]+v[2])/3; printf("语文:%d\nc数学:%d\n英语:%d\n", v[0], v[1], v[2]); printf("全体平均:%d\n", average ); }
上述代码首先用了一个双重循环,在内循环中依次读入某一门课程的每个学生的成绩。然后把这些成绩累加起来,退出内循环后再把该累加成绩除以5送入v[i]之中,这就是该门课程的平均成绩。外循环共循环3次,分别求出3门课各自的平均成绩并存放在数组v之中。退出外循环之后,把v[0]、v[1]、v[2]相加除以3即得到各科总平均成绩,最后按要求输出各个成绩。
3.初始化二维数组
初始化二维数组是在类型说明时,为各下标变量赋初始值。C语言中的二维数组可按行分段赋值,也可按行连续赋值。
例如可以使用如下两种方式对数组a[4][2]进行初始化赋值。
❑ 按行分段赋值,具体如下所示。
int a[4][2]={ {80,75}, {91,95}, {59,93}, {85,87} }; int a[4][2]={ 80,75,91,95, 59,93,85,87};
❑ 按行连续赋值,具体如下所示。
对二维数组进行赋值时,应该注意如下3点。
(1)可以只对部分元素赋初值,未赋初值的元素自动赋值为零。例如下面代码是对每一行的第1列元素赋值,未赋值的元素取值为0:
int a[3][3]={{1}, {2}, {3}};
上述赋值后,各个元素的值如下。
1 0 0
2 0 0
3 0 0
(2)如果对全部元素赋初值,则可以不给出第一维的长度。例如,下面的两种格式是相同的。
int a[3][3]={1,2,3,4,5,6,7,8,9}; int a[][3]={1,2,3,4,5,6,7,8,9};
(3)数组是一种构造类型的数据,二维数组可以看作是由一维数组嵌套而构成的。
实例8-3
在屏幕中实现10行杨辉三角的效果
源码路径daima\8\8-3
杨辉三角是两个未知数相加后求幂次方运算后的系数问题,比如(x+y)2=x2+2xy+y2,它的系数分别是1、2、1,这就是杨辉三角的其中一行,进行立方、四次方运算后观察各项的系数。
杨辉三角是一个由数字排列成的三角形数表,一般形式如下。
1 n=0 1 1 n=1 1 2 1 n=2 1 3 3 1 n=3 1 4 6 4 1 n=4 1 5 10 10 5 1 n=5 1 9 15 20 15 9 1 n=9
杨辉三角的特点如下所示。
❑ 与二项式定理的关系:杨辉三角的第n行就是二项式展开式的系数列。
❑ 对称性:杨辉三角中的数字左、右对称,对称轴是杨辉三角形底边上的“高”。
❑ 结构特征:杨辉三角中除斜边上第一个1以外的各数,都等于它“肩上”的两数之和。
❑ 这些数排列的形状像等腰三角形,两腰上的数都是1。
❑ 第n行数字的和为2n-1。
❑ 每个数字等于上一行的左右两个数字之和。
❑ (a+b)n的展开式中的各项系数依次对应杨辉三角第(n+1)行中的每一项。
本实例的实现文件为“yang.c”,具体实现代码如下所示。
#define N 11 int main(void){ int i, j, a[N][N]; //定义两个整型变量和一个二维数组 for(i=1; i<N; i++)//存储杨辉三角中两条斜边的数字 { a[i][i]=1; a[i][1]=1; } for(i=3; i<N; i++)//打印出杨辉三角中每一行中间的数 for(j=2; j<i; j++) a[i][j]=a[i-1][j-1]+a[i-1][j]; for(i=1; i<N; i++) //输出杨辉三角 { for(j=1; j<=i; j++) printf("%4d", a[i][j]); printf("\n"); } }
拓展范例及视频二维码
范例8-3-01:处理学生的成绩
源码路径:演练范例\8-3-01\

范例8-3-02:实现矩阵转置处理
源码路径:演练范例\8-3-02\

上述代码的具体实现流程如下所示。
(1)通过“N 11”设置循环执行10次,即输出10行杨辉三角。
(2)分别声明两个整型变量i、j和数组a[N][N]。
(3)循环执行10次。
(4)for嵌套循环for(i=3; i<N; i++),用于输出杨辉三角中每一行中间的数。
(5)for嵌套循环for(i=1; i<N; i++),用于输出杨辉三角。
程序执行后将在界面中输出20行杨辉三角,如图8-3所示。

图8-3 运行结果