二维数组
三个学生,每人考了四门。这样的数据天生是一张表:一行一个学生,一列一门课。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 | |
|---|---|---|---|---|
| 行 0 | 80 | 92 | 75 | 68 |
| 行 1 | 95 | 88 | 90 | 79 |
| 行 2 | 60 | 71 | 85 | 93 |
用嵌套循环走一遍
外层循环走每一行,内层循环走这一行的每一列。一行打完,换行。点单步,看 row 和 col 是怎么一起变的:
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}
g[1] 是第二行 {3, 4},g[1][0] 是这一行的第一个,就是 3。先行,后列。
每一行的总分
每个学生的总分,就是把一行加起来。每换一行,total 要重新从 0 开始,所以它写在外层循环里面:
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
每一列的平均
每门课的平均分,要把一列加起来。这次反过来:外层循环走列,内层循环走行。
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],先行后列,变的只是哪个循环在外面。
矩阵相加
数学里一张数字表叫矩阵。两个一样大的矩阵相加,就是同一个位置上的数相加。比如两家店两天里三种水果的销量,加起来就是总销量:
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。
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}; 把整张表清零。
练一练
写好代码,点检查。提示随便看,实在想不出来再看答案。
全部加起来
✓sales 是两周、每周 7 天的销量。算出两周一共卖了多少,显示 一共:98。
一共:98
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}
转过来
✓把 2 行 3 列的 m 转成 3 行 2 列显示:原来的第 0 列变成第 0 行,以此类推。每个数用 %4d。
1 4 2 5 3 6
1#include <stdio.h>2 3int main(void) {4 int m[2][3] = {{1, 2, 3}, {4, 5, 6}};5 6 return 0;7}
哪里最热
✓temps 是 3 天、每天 4 个时刻的温度。找出最高的温度和它在哪里,显示 最高 31 度:第 2 天,第 3 次(天和次数都从 1 数起)。
最高 31 度:第 2 天,第 3 次
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}
这一课学会了
- 二维数组像一张表:
int a[3][4]是 3 行 4 列,一组花括号是一行。 - 取元素写两个下标,先行后列:
a[row][col],都从0开始。 - 用嵌套循环走一遍:外层走行、内层走列;要按列算,就把列放在外层。
- 矩阵相加:同一个位置的数相加,放进第三个数组。
- 在内存里是一行接一行地放;
sizeof a / sizeof a[0]是行数,sizeof a[0] / sizeof a[0][0]是列数。