一維數組名作參數退化為T*(指向首元素)。**多維數組只退化第一維**,保留後續維度信息:
int a[3][4] → 參數類型 int (*)[4] (**指向含4個int數組的指針**),而非int**。int a[2][3][4] → int (*)[3][4]。原因:函數內需要知道「行長度」以計算a[i][j]偏移(i*COLS + j),編譯器必須在類型中編碼COLS。
對 float a[3][4],以下聲明**完全等價**:
void func1(float a[3][4]); // 1. 形式數組聲明 (第一維忽略)
void func2(float a[][4]); // 2. 省略第一維 (推薦,清晰表達「行數不定,列數固定4」)
void func3(float (*a)[4]); // 3. 顯式指針聲明 (本質)
void func4(float *a); // 4. 扁平化指針 (需手動計算偏移 a[i*4+j])
調用時均可傳 a、a[0]、&a[0][0]。
#include <stdio.h>
void print_student_scores(float (*scores)[4], int student_idx) {
// scores 指向「含4個float的數組」的指針
for (int j = 0; j < 4; ++j)
printf("%7.2f", scores[student_idx][j]); // scores[student_idx] 退化為 float*
printf("\n");
}
void print_all_avg(float *scores_flat, int total_count) {
// 扁平化視圖:視為一維數組
float sum = 0;
for (int i = 0; i < total_count; ++i) sum += scores_flat[i];
printf("avg=%7.2f\n", sum / total_count);
}
int main() {
float scores[3][4] = {
{97, 45.5, 66, 77},
{88, 92.5, 78.5, 66},
{83, 74.5, 92, 100}
};
print_student_scores(scores, 0); // 打印第0個學生
print_all_avg(&scores[0][0], 3 * 4); // 扁平化傳遞計算總平均
return 0;
}
編譯時未知列數,無法用float (*)[COLS]。兩種方案:
float **a (非連續內存)float **alloc_2d_ptr(int rows, int cols) {
float **a = malloc(rows * sizeof(float*));
for (int i = 0; i < rows; ++i)
a[i] = malloc(cols * sizeof(float));
return a;
}
void func_ptr(float **a, int rows, int cols) { a[i][j] = ...; }
// 釋放需反向循環 free(a[i]) 後 free(a)
優點:行長度可變、語法a[i][j]自然。缺點:內存不連續、緩存不友好、分配/釋放慢、碎片化。
float *a (推薦高性能)float *alloc_2d_flat(int rows, int cols) {
return malloc(rows * cols * sizeof(float)); // 單塊連續
}
void func_flat(float *a, int rows, int cols) {
a[i * cols + j] = ...; // 手動計算偏移
}
// 或封裝宏/內聯函數
#define AT(a, i, j, cols) ((a)[(i)*(cols) + (j)])
// 釋放單次 free(a)
優點:**內存連續、緩存友好、單次分配/釋放、易於向量化/SIMD、便於傳遞給BLAS/LAPACK/GPU**。缺點:語法稍繁,需傳遞cols。
void func_vla(int rows, int cols, float a[rows][cols]) {
a[i][j] = ...; // 編譯器自動計算偏移,內存連續
}
調用:func_vla(3, 4, scores);。注意:大尺寸VLA導致棧溢出,僅用於小/中等規模。
std::array<std::array<float, 4>, 3> 或 std::mdspan<float, std::extents<3, 4>> (C++23)。std::vector<float> 扁平化 + std::mdspan (C++23) 視圖,或自定義 Matrix 類封裝 operator()(i,j)。new float*[rows]、std::vector<std::vector<float>> (非連續)。| 場景 | 推薦類型 | 關鍵點 |
|---|---|---|
| 編譯時知列數 | T (*)[COLS] / T[][COLS] | 保留類型信息,語法自然 |
| 運行時定維度,高性能 | T* (扁平化) + cols | 連續內存,手動偏移,最快 |
| 運行時定維度,行長度可變 | T** (指針數組) | 非連續,靈活但慢 |
| C99 小規模 | VLA T[rows][cols] | 自動偏移,棧分配風險 |
| C++ 現代 | std::mdspan / 封裝類 | 類型安全,零開銷,表達力強 |
**核心原則**:內存佈局決定性能。理解「行優先、連續為王」,在C用扁平化+mdspan思想,在C++直接用mdspan/容器,是處理多維數據的正道。