定义
二维数组本质上是数组的数组,即外层数组的每个元素都是一个一维数组,由行和列两部分构成,属于多维数组。可以按照先行后列的方式解读。
二维数组可被视为一个特殊的一维数组,也就是说,当一个数组的每一个元素都是移位数组的时候,那么这个数组就是二维数组。
语法
数据类型 数组名[行容量][列容量] //行容量指的是外层数组的数组容量,也就是二维数组中一维数组的个数 //列容量指的是内层数组的数组容量,也就是二一维数组的元素个数
说明
-
二维数组在初始化的时候,可以省略行数,系统会通过初始化后的数据自动推断行数。
-
二维数组和一维数组一样,也可以部分初始化,未初始化的元素使用0进行填充(无论是全局作用域还是局部作用域)
-
二维数组在初始化的时候,不能省略列数,否则编译报错。
举例
//推荐写法:省略行容量(编译器会自动推断),分行初始化 int arr[][3]//写法不对,因为未初始化 int arr[][3] = {{11,12,13},{11,12,13},{11,12,13}};//写法正确,编译器自动推断除行数为3 //部分初始化未初始化的元素自动补0(二维数组中所有一维数组的大小一致) int arr[3][3] = {{1,2},{3,4,5},{6}};//等价于{{1,2,0},{3,4,5},{6,0,0}} int arr[][3] = {{1,2},{3,4,5},{6}}};//等价于{{1,2,0},{3,4,5},{6,0,0}} //{}空初始化列表,c89标准不支持(编译报错),C99及以上标准支持(静态/全局均会全0初始化) int arr[3][3] = {};//等价{{0,0,0},{0,0,0},{0,0,0}} int arr[3][3] = {0};//等价{{0,0,0},{0,0,0},{0,0,0}} int arr[][]={{1,2,0},{3,4,5},{6,0,0}};//编译报错
注意:C语言中二维数组按行优先 存储:先连续存储第0行的所有列元素,再存储第1行的所有列元素,以此类推;反映在下标上,行下标(第一维)变化慢,列下标(第二维)变化快(例如arr[2][3]先填满arr[0][0]->arr[0][1]->arr[0][2]再到arr[1][0]->arr[1][1]->arr[1][2]).
内存存储
注:这里的地址仅为了方便区分,实际的地址表示为12位十六进制整数。
应用场合
主要是应用对行列有要求的情况,比如说要存储一个年纪所有班级的学生成绩。
还有字符数组的应用,比如用数组存储学生姓名。
double score[30] = {};
double score[8][30] = {};
double score[6][8][30] = {};
特殊写法
下标可以是整型表达式。如a[2-1][2*2-1]访问的是a[1][3]
下标可以是已经有值的变量或者数组元素。如a[2*x-1][b[3][1]][]中最终需要的是一个>=0且小于数组对应维度容量的整数(下标从0开始)。
数组元素可以出现在表达式中,如b[1][2] = a [2][3]/2(考试用,开发不用)
演示
| 数组:arr | 列0 | 列1 | 列2 | 举例 | 说明 |
|---|---|---|---|---|---|
| 行0 | 11 | 12 | 13 | arr[0][1] |
数组arr的0行1列对应的元素 |
| 行1 | 21 | 22 | 23 | arr[1][2] |
数组arr的1行2列对应的元素 |
注意:使用数组元素的下标应在已定义数组的大小范围内;应注意区别定义数组大小和引用数组元素的区别。
初始化
//分行给二维数组赋初值 int arr[3][3] = {{1,2,3},{4,5,6},{7,8,9}} // int arr[3][3] = {1,2,3,4,5,6,7,8,9}; // int arr[3][3] = {{1},{2,3},{4}}; int arr[3][3] = {1,2,3,4};
案例
案例1:二维数组的遍历
-
分析:
-
二维数组本质上属于行列式,遍历的时候需要借助嵌套的for循环,外层for负责行的遍历,内层for负责列的遍历。
-
取值
数组名[行下标][列下标]; -
赋值
数组名[行下标][列下标] = 值; -
行和列的容量计算
//计算行的大小 int row_len = sizeof(arr) / sizeof(arr[行下标0]); //计算列的大小 int col_len = sizeof(arr[行下标0]) / sizeof(arr[行下标0][列下标0]); -
代码
#include <stdio.h> int main(int argc,char *argv[]) { int arr[3][3] = {1,2,3,4,5,6,7,8,9}; int arr_row = sizeof(arr) / sizeof(arr[0]); int arr_col = sizeof(arr[0]) / sizeof(arr[0][0]); for(int i = 0; i < arr_row; i++) { for(int j = 0; j < arr_col; j++) { printf("%-4d",arr[i][j]); } printf("\n"); } printf("\n"); return 0; } -
结果

-
案例2:矩阵的转置
-
分析
- 所谓的转置,就是原本的列变行,行变列

- 所谓的转置,就是原本的列变行,行变列
-
代码
#include <stdio.h> //定义行列宏 #define ROW 2 #define COL 3 int main(int argc,char *argv[]) { int i, j;//定义循环变量 //准备2个数组,用来存放转置前后的数据 int arr_before[ROW][COL] = {11,12,13,21,22,23}; int arr_after[COL][ROW] = {0}; //计算数组的大小 int arr_before_row = sizeof(arr_before) / sizeof(arr_before[0]); int arr_before_col = sizeof(arr_before[0]) / sizeof(arr_before[0][0]); int arr_after_row = sizeof(arr_after) / sizeof(arr_after[0]); int arr_after_col = sizeof(arr_after[0]) / sizeof(arr_after[0][0]); //循环遍历二维数组 printf("\n转置前:\n"); for(i = 0; i < arr_before_row; i++) { for(j = 0; j < arr_before_col; j++) { //打印转置前的数据 printf("%-4d",arr_before[i][j]); //转置:行变列,列变行 arr_after[j][i] = arr_before[i][j]; } printf("\n"); } printf("\n转置后:\n"); for(i = 0; i < arr_after_row; i++) { for(j = 0; j < arr_after_col; j++) { printf("%-4d",arr_after[i][j]); } printf("\n"); } printf("\n"); return 0; } -
结果

课堂练习
- 需求:求一个3行3列的矩阵对角线元素相