二維數組:從定義到高級用法全解析
定義與初始化
int a[3][4] = {0}; // 全零初始化
int b[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}}; // 分行初始化
int c[][4] = {{1,2}, {3}}; // 省略行數,列數必須給定
// 內存佈局:行優先,連續存儲 12 個 int
鍵盤輸入 (雙層循環)
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 4; ++j)
scanf("%d", &a[i][j]); // &a[i][j] 等價於 *(a+i)+j
格式化輸出
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j)
printf("%4d", a[i][j]); // %4d 對齊列
putchar('\n');
}
作為函數參數傳遞 (三種等價寫法)
// 1. 指針數組 (列數固定)
void print1(int a[][4], int rows) { ... }
void print1(int (*a)[4], int rows) { ... } // 指向含4個int數組的指針
// 2. 一維指針 + 手動計算下標 (最靈活)
void print2(int *a, int rows, int cols) {
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
printf("%d ", a[i*cols + j]);
}
// 3. 變長數組 VLA (C99, C11可選)
void print3(int rows, int cols, int a[rows][cols]) { ... }
動態分配二維數組
// 方法一:指針數組 + 每行獨立 malloc (行不連續)
int **p = malloc(rows * sizeof(int*));
for (int i = 0; i < rows; ++i) p[i] = malloc(cols * sizeof(int));
// 釋放時需逐行 free 再 free(p)
// 方法二:單塊連續內存 + 指針數組映射 (推薦,緩存友好)
int *data = malloc(rows * cols * sizeof(int));
int **p = malloc(rows * sizeof(int*));
for (int i = 0; i < rows; ++i) p[i] = data + i * cols;
// 釋放:free(data); free(p);
// 方法三:C99 VLA (棧上,自動釋放,大小受限)
int n, m; scanf("%d%d", &n, &m);
int a[n][m]; // 直接用
常見錯誤
scanf("%d", a[i][j]) 缺 &。
- 函數參數寫
int a[][] (編譯錯誤,需指定列數或用指針)。
- 動態分配後忘記檢查
NULL 或忘記 free 導致洩漏。
- 用
sizeof(a) 在函數內獲取大小 → 退化為指針,只得指針大小。
練習建議
- 實現矩陣轉置、乘法、鞍點查找。
- 用二維數組實現迷宮走法 (BFS/DFS)。
- 對比靜態、VLA、動態三種方式的性能與適用場景。