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 运行结果