Kodewick
第 12 课,共 30 课目录

二维数组

第 12 课,共 30 课 · 第 2 部分 · 函数和数组 · 约 15 分钟

三个学生,每人考了四门。这样的数据天生是一张表:一行一个学生,一列一门课。C 用二维数组放它:

main.c
1#include <stdio.h>2 3int main(void) {4    int scores[3][4] = {5        {80, 92, 75, 68},6        {95, 88, 90, 79},7        {60, 71, 85, 93}8    };9    printf("第 1 个学生的第 1 门:%d\n", scores[0][0]);10    printf("第 3 个学生的第 4 门:%d\n", scores[2][3]);11    return 0;12}
输出
第 1 个学生的第 1 门:80
第 3 个学生的第 4 门:93

int scores[3][4] 是 3 行、4 列,一共 12 个 int。花括号里一组花括号是一行。取一个元素要写两个下标:先行,后列。两个下标都从 0 开始:

列 0列 1列 2列 3
行 080927568
行 195889079
行 260718593

用嵌套循环走一遍

外层循环走每一行,内层循环走这一行的每一列。一行打完,换行。点单步,看 row 和 col 是怎么一起变的:

main.c
1#include <stdio.h>2 3int main(void) {4    int grid[2][3] = {5        {1, 2, 3},6        {4, 5, 6}7    };8    for (int row = 0; row < 2; row++) {9        for (int col = 0; col < 3; col++) {10            printf("%4d", grid[row][col]);11        }12        printf("\n");13    }14    return 0;15}
输出
   1   2   3
   4   5   6

%4d 让每个数占 4 格(第 3 课讲过),这样一列一列就对齐了。

先猜一猜

这段程序显示什么?

1#include <stdio.h>2 3int main(void) {4    int g[3][2] = {5        {1, 2},6        {3, 4},7        {5, 6}8    };9    printf("%d\n", g[1][0]);10    return 0;11}

每一行的总分

每个学生的总分,就是把一行加起来。每换一行,total 要重新从 0 开始,所以它写在外层循环里面:

main.c
1#include <stdio.h>2 3int main(void) {4    int scores[3][4] = {5        {80, 92, 75, 68},6        {95, 88, 90, 79},7        {60, 71, 85, 93}8    };9    for (int s = 0; s < 3; s++) {10        int total = 0;11        for (int c = 0; c < 4; c++) {12            total += scores[s][c];13        }14        printf("学生 %d:总分 %d,平均 %.2f\n", s + 1, total, total / 4.0);15    }16    return 0;17}
输出
学生 1:总分 315,平均 78.75
学生 2:总分 352,平均 88.00
学生 3:总分 309,平均 77.25

每一列的平均

每门课的平均分,要把一列加起来。这次反过来:外层循环走列,内层循环走行。

main.c
1#include <stdio.h>2 3int main(void) {4    int scores[3][4] = {5        {80, 92, 75, 68},6        {95, 88, 90, 79},7        {60, 71, 85, 93}8    };9    for (int c = 0; c < 4; c++) {10        int total = 0;11        for (int s = 0; s < 3; s++) {12            total += scores[s][c];13        }14        printf("第 %d 门:平均 %.1f\n", c + 1, total / 3.0);15    }16    return 0;17}
输出
第 1 门:平均 78.3
第 2 门:平均 83.7
第 3 门:平均 83.3
第 4 门:平均 80.0

下标还是 scores[s][c],先行后列,变的只是哪个循环在外面。

矩阵相加

数学里一张数字表叫矩阵。两个一样大的矩阵相加,就是同一个位置上的数相加。比如两家店两天里三种水果的销量,加起来就是总销量:

main.c
1#include <stdio.h>2 3int main(void) {4    int shopA[2][3] = {{5, 3, 8}, {6, 2, 7}};5    int shopB[2][3] = {{4, 9, 1}, {3, 5, 2}};6    int sum[2][3];7    for (int r = 0; r < 2; r++) {8        for (int c = 0; c < 3; c++) {9            sum[r][c] = shopA[r][c] + shopB[r][c];10        }11    }12    for (int r = 0; r < 2; r++) {13        for (int c = 0; c < 3; c++) {14            printf("%4d", sum[r][c]);15        }16        printf("\n");17    }18    return 0;19}
输出
   9  12   9
   9   7   9

sum 一开始没赋值,第一组循环把 6 个格子都填上,第二组循环再显示。

在内存里怎么放

内存是一长条,没有「行」和「列」。二维数组其实是一行接着一行地放:先放第 0 行的全部,再放第 1 行。所以 grid[2][3] 就是 6 个 int 连在一起,grid[0] 是其中一行,3 个 int。

main.c
1#include <stdio.h>2 3int main(void) {4    int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};5    int rows = sizeof grid / sizeof grid[0];6    int cols = sizeof grid[0] / sizeof grid[0][0];7    printf("整个:%zu 字节\n", sizeof grid);8    printf("一行:%zu 字节\n", sizeof grid[0]);9    printf("%d 行 %d 列\n", rows, cols);10    return 0;11}
输出
整个:24 字节
一行:12 字节
2 行 3 列

和一维数组一样,sizeof 能算出有几行、每行几列。下标也一样不能越界:grid[0][3] 在内存里虽然紧挨着 grid[1][0],也还是越界,引擎会停下来。

小技巧: 给的值不够,剩下的是 0:int table[3][4] = {0}; 把整张表清零。

练一练

写好代码,点检查。提示随便看,实在想不出来再看答案。

练习 1

全部加起来

sales 是两周、每周 7 天的销量。算出两周一共卖了多少,显示 一共:98。

要显示
一共:98
exercise1.c
1#include <stdio.h>2 3int main(void) {4    int sales[2][7] = {5        {5, 8, 6, 7, 9, 12, 4},6        {6, 7, 5, 8, 10, 7, 4}7    };8 9    return 0;10}
输出
点「运行」或按 Ctrl+Enter
练习 2

转过来

把 2 行 3 列的 m 转成 3 行 2 列显示:原来的第 0 列变成第 0 行,以此类推。每个数用 %4d。

要显示
   1   4
   2   5
   3   6
exercise2.c
1#include <stdio.h>2 3int main(void) {4    int m[2][3] = {{1, 2, 3}, {4, 5, 6}};5 6    return 0;7}
输出
点「运行」或按 Ctrl+Enter
练习 3

哪里最热

temps 是 3 天、每天 4 个时刻的温度。找出最高的温度和它在哪里,显示 最高 31 度:第 2 天,第 3 次(天和次数都从 1 数起)。

要显示
最高 31 度:第 2 天,第 3 次
exercise3.c
1#include <stdio.h>2 3int main(void) {4    int temps[3][4] = {5        {18, 24, 27, 20},6        {19, 26, 31, 22},7        {17, 23, 29, 21}8    };9 10    return 0;11}
输出
点「运行」或按 Ctrl+Enter

这一课学会了

  • 二维数组像一张表:int a[3][4] 是 3 行 4 列,一组花括号是一行。
  • 取元素写两个下标,先行后列:a[row][col],都从 0 开始。
  • 用嵌套循环走一遍:外层走行、内层走列;要按列算,就把列放在外层。
  • 矩阵相加:同一个位置的数相加,放进第三个数组。
  • 在内存里是一行接一行地放;sizeof a / sizeof a[0] 是行数,sizeof a[0] / sizeof a[0][0] 是列数。