需將二維數組 rain[5][12] 複製到 t1[5][12],要求函數使用指針語法而非下標語法完成拷貝,並能處理任意行列數。
void copy_ptr(const double (*src)[12], double (*dst)[12], int rows, int cols);
const double (*src)[12]:指向「含 12 個 double 的數組」的指針,即指向二維數組的一行(子數組)。const 保護源數據不被修改。double (*dst)[12]:目標數組同類型指針。rows, cols:運行時傳入的實際維度,解耦函數與固定列數 12。src + i:指向第 i 行(偏移 i * 12 * sizeof(double) 字節)。*(src + i):解引用得到第 i 行的首元素地址(類型 double *)。*(*(src + i) + j):等價於 src[i][j],訪問第 i 行第 j 列元素。#includevoid copy_ptr(const double (*src)[12], double (*dst)[12], int rows, int cols) { for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { *(*(dst + i) + j) = *(*(src + i) + j); } } } int main(void) { const double rain[5][12] = { {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6}, {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3}, {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4}, {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2}, {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2} }; double t1[5][12] = {0}; copy_ptr(rain, t1, 5, 12); // 驗證輸出 for (int i = 0; i < 5; ++i) { for (int j = 0; j < 12; ++j) printf("%.1f%c", t1[i][j], j==11?'\n':' '); } return 0; }
二維數組在內存中是連續一維數組的集合。類型系統視角:
double [5][12] → 5 個 double [12] 的數組double (*)[12](指向首個 double [12] 的指針)* 降低一維:*p 得到 double [12],再退化為 double *這形成一條指針鏈:double (*)[12] → double * → double,每層步長不同,編譯器根據類型自動計算偏移。
void copy_vla(int rows, int cols, const double src[rows][cols], double dst[rows][cols]) {
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
dst[i][j] = src[i][j]; // 下標語法更清晰,編譯器同樣生成指針算術
}
VLA 允許運行時確定維度,調用時無需固定列數,更靈活。
| 錯誤寫法 | 問題 | 正確寫法 |
|---|---|---|
void f(double **a) | 指針數組 ≠ 二維數組,內存佈局不同 | void f(double (*a)[COLS]) 或 VLA |
void f(double a[][]) | 缺少列數,編譯器無法計算行步長 | 必須指定列數或用 VLA |
忽略 const | 源數組可被意外修改 | 加 const 保護只讀參數 |