| 特性 | 陣列名 (arr) | 指針變量 (p) |
| 存儲位置 | 棧區(靜態分配) | 指針變量在棧,指向堆/棧/數據區 |
| 可修改性 | 常量,不可賦值/自增 | 變量,可指向任意合法地址 |
| sizeof 結果 | 整個陣列大小(字節數) | 指針大小(4/8字節) |
| 類型 | int [10] → 退化為 int* | int* |
三、指針陣列 vs 二維陣列
// 指針陣列:每個元素是指針
int *ptr_arr[5] = {&a, &b, &c, &d, &e};
printf("%d", *ptr_arr[i]); // 需解引用
// 二維陣列:連續內存塊
int matrix[3][4];
printf("%d", matrix[i][j]); // 編譯器計算偏移:i*4+j
四、動態分配陣列
// 一維動態陣列
int *p = malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) p[i] = i + 1;
// 指針陣列動態分配(鋸齒陣列)
int **jagged = malloc(5 * sizeof(int*));
for (int i = 0; i < 5; i++) {
jagged[i] = malloc(sizeof(int));
*jagged[i] = i;
}
// 二維動態陣列(連續內存)
int rows = 3, cols = 4;
int **mat = malloc(rows * sizeof(int*));
mat[0] = malloc(rows * cols * sizeof(int)); // 一塊連續內存
for (int i = 1; i < rows; i++) mat[i] = mat[0] + i * cols;
五、二維陣列作函數參數
子函數無法直接用 arr[i][j],需退化為一維指針並手動計算偏移:
void init(int *arr, int rows, int cols) {
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
*(arr + i * cols + j) = ...; // 手動偏移
}
int main() {
int a[5][6];
init(&a[0][0], 5, 6); // 傳首元素地址
}
六、經典代碼示例
// 指針陣列遍歷
int *num1[3];
int num2[3] = {1, 2, 3};
for (int i = 0; i < 3; i++) num1[i] = &num2[i];
for (int i = 0; i < 3; i++) printf("%4d", *num1[i]);
// 二維陣列統一初始化/打印
void arr_init(int *arr, int rows, int cols) { ... }
void arr_print(int *arr, int rows, int cols) { ... }
int main() {
int n1[5][6], n2[7][8];
arr_init(&n1[0][0], 5, 6);
arr_print(&n1[0][0], 5, 6);
arr_init(&n2[0][0], 7, 8);
arr_print(&n2[0][0], 7, 8);
}
七、核心心法
- 陣列名不是指針,只是在大多數表達式中「退化」為首元素指針
- sizeof 是編譯時運算符,能分辨陣列與指針
- 函數參數退化:
void f(int a[]) 等價於 void f(int *a)
- 動態分配二維陣列:首選「指針陣列+連續數據塊」模式,兼顧
arr[i][j] 語法與內存連續性
指針與陣列的區別是C語言進階的分水嶺,徹底理解內存模型、類型系統與編譯器行為,方能寫出健壯高效的代碼。
- 上一篇文章: 編程算法精髓:不使用四則運算實現加法(位運算實現)
- 下一篇文章: C語言字符串函數完全指南:strcpy、strcat、strcmp、strlen 實戰詳解
Copyright ©
程式碼之家 All Rights Reserved