一维数组是一条线,二维数组是一张表(行列),三维数组是一摞表。多维数组在 C 语言里就是把多个方向的格子按顺序排进内存,配合嵌套循环访问。下面讲二维、三维数组怎么用。
什么是多维数组
多维数组就是超过一维的数组。最常见的是二维(存表格、矩阵)和三维(存分层、体数据):
- 二维数组用"行 + 列"存数据,适合表格和矩阵。
- 三维数组用"层 + 行 + 列"存数据,适合分层或体块数据。
最快上手的方式是直接看声明和遍历:
#include <stdio.h>
int main() {
/* 声明并初始化一个 2×2 的整数数组 */
int arr[2][2] = { {10, 20}, {30, 40} };
printf("2D Array Elements:\n");
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}输出:
2D Array Elements:
10 20
30 40声明语法
N 维数组的通用写法:
type arrName[size1][size2]....[sizeN];- type:数组里装的数据类型
- arrName:数组名
- size1..sizeN:每一维的大小
二维:
int arr[10][20]; /* 10 行 20 列 */数组有多大
元素总数 = 各维相乘。内存占用 = 元素总数 × 单个元素大小:
int arr[10][20]:10 × 20 = 200 个元素- int 占 4 字节:200 × 4 = 800 字节
用 sizeof 也能算(在声明它的作用域里才行):
int arr[10][20];
size_t total = sizeof(arr); /* 整个二维数组的字节数 */
size_t rows = sizeof(arr) / sizeof(arr[0]); /* 10 */
size_t cols = sizeof(arr[0]) / sizeof(arr[0][0]); /* 20 */二维数组的初始化
两种写法等价,推荐带内层花括号的,每一行清清楚楚:
int arr[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
/* 或 */
int arr[3][4] = { {0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11} };初始化按从左到右、从上到下填,每组内层花括号是一行。第一维可以省略,列数必须写出来,编译器要靠它算行的位置:
int arr[][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} }; /* 3 行自动算出 */初值个数 ≤ 数组总容量,缺的补 0。
访问元素
用"行索引 + 列索引",都是 0 起:
int arr[5] = {2, 4, 8, 12, 16};
/* 一维的访问复习一下 */
printf("%d\n", arr[2]); /* 8 */
int mat[3][2] = { {0, 1}, {2, 3}, {4, 5} };
printf("%d\n", mat[1][0]); /* 第二行第一个 = 2 */
printf("%d\n", mat[0][1]); /* 第一行第二个 = 1 */遍历二维数组
标准的做法是嵌套循环:外层管行,内层管列。
#include <stdio.h>
int main() {
int arr[3][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
printf("arr[%d][%d]: %d ", i, j, arr[i][j]);
}
printf("\n");
}
return 0;
}输出:
arr[0][0]: 0 arr[0][1]: 1
arr[1][0]: 2 arr[1][1]: 3
arr[2][0]: 4 arr[2][1]: 5改值也一样,比如 arr[0][0] = 1;。
二维数组在内存里怎么排
内存是线性的,二维数组也得排成一条线。C 语言用的是行优先(row-major):先放完第一行,再放第二行。另一种叫列优先(column-major),先放完第一列,那是 Fortran 的做法,C 不用。
int mat[2][3] = {{1, 2, 3}, {4, 5, 6}};
内存顺序:1 2 3 4 5 6
└第一行┘ └第二行┘程序只需要记住数组的基地址,任何一个元素都能用"基地址 + 偏移"直接算出,这就是随机访问高效的底气。
把二维数组传给函数
传二维数组给函数,形参得写成指针数组,列数必须带上:
void print2D(int arr[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main() {
int mat[2][3] = { {1, 2, 3}, {4, 5, 6} };
print2D(mat, 2);
return 0;
}因为参数里的数组会退化成指针,编译器需要知道每行多宽(列数)才能算地址,所以列数不能省。行数传不传都行,反正循环里自己控制。
三维数组
三维 = 一组二维数组叠起来。声明:
type arr_name[x][m][n]; /* x 层,每层 m 行 n 列 */
int arr[2][2][2]; /* 2 层,每层 2×2 */初始化,维数越多花括号越厚:
int arr[2][3][2] = { { {1, 1}, {2, 3}, {4, 5} },
{ {6, 7}, {8, 9}, {10, 11} } };第一维可省略,其余维必须写:
int arr[][3][2] = { /* ... */ };访问用三个索引(层、行、列):
arr_name[d][i][j]遍历要用三重循环:外层管层,中层管行,内层管列。
#include <stdio.h>
int main() {
int arr[2][3][2] = { { {1, 1}, {2, 3}, {4, 5} },
{ {6, 7}, {8, 9}, {10, 11} } };
for (int i = 0; i < 2; ++i) { /* 层 */
for (int j = 0; j < 3; ++j) { /* 行 */
for (int k = 0; k < 2; ++k) /* 列 */
printf("arr[%d][%d][%d] = %d ", i, j, k, arr[i][j][k]);
printf("\n");
}
printf("\n\n");
}
return 0;
}输出:
arr[0][0][0] = 1 arr[0][0][1] = 1
arr[0][1][0] = 2 arr[0][1][1] = 3
arr[0][2][0] = 4 arr[0][2][1] = 5
arr[1][0][0] = 6 arr[1][0][1] = 7
arr[1][1][0] = 8 arr[1][1][1] = 9
arr[1][2][0] = 10 arr[1][2][1] = 11三维在内存里一层一层排:先存第一层(按行优先),再存第二层。传给函数时,除了第一维,其余维的大小都要在形参里写清楚,道理和二维一样。
什么时候用多维数组
- 矩阵运算:线性代数、图像处理。
- 表格数据:学生成绩表、库存表。
- 游戏棋盘/地图:二维格子天然契合。
- 体素数据:三维网格、CT 切片这类。
数据只要规则、方整、按行按列取,多维数组就是最顺手的容器。