首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C/C++多維數組指針作為函數參數傳遞完全指南

     編輯:關於C語言

核心難點:多維數組退化規則

一維數組名作參數退化為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。

方案三:C99 變長數組 (VLA) 參數 (C99, C11可選, C++不支持)

void func_vla(int rows, int cols, float a[rows][cols]) {
    a[i][j] = ...; // 編譯器自動計算偏移,內存連續
}

調用:func_vla(3, 4, scores);。注意:大尺寸VLA導致棧溢出,僅用於小/中等規模。

C++ 現代最佳實踐

  • 固定維度: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/容器,是處理多維數據的正道。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved