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

C語言二維陣列傳參完整指南:指標與陣列的本質差異

     編輯:關於C

二維陣列傳參核心問題

許多 C 開發者嘗試寫通用矩陣運算函數時,會遇到經典編譯錯誤:

void matrix_mult(float **p);  // 錯誤宣告
float a[3][3];
matrix_mult(a);  // error: cannot convert 'float [3][3]' to 'float **'

正確宣告方式

// 正確:指向固定行長度陣列的指標
void matrix_mult(float (*p)[N]);  // N 為第二維大小
matrix_mult(a);  // 編譯通過

根本原因:陣列與指標的本質差異

關鍵類型對照表


int a[10][20];        // 真正的二維陣列,連續記憶體 10×20×4 bytes
int *b[10];           // 指標陣列:10 個 int*,各自指向獨立記憶體
int (*p)[3];          // 陣列指標:指向「含 3 個 int 的陣列」
int (*p)();           // 函數指標:指向回傳 int 的函數
int *p();             // 函數宣告:回傳 int* 的函數
float **p;            // 二級指標:指向指標的指標,非二維陣列

為何 float ** ≠ 二維陣列?

二維陣列 a[3][3] 記憶體佈局:
[a[0][0]] [a[0][1]] [a[0][2]] [a[1][0]] [a[1][1]] [a[1][2]] [a[2][0]] [a[2][1]] [a[2][2]]
 ↑ 基址連續 27 個 float

float **p 記憶體佈局:
p → [ptr0] → [row0: 3 floats]
    [ptr1] → [row1: 3 floats]  
    [ptr2] → [row2: 3 floats]
 ↑ 間接存取,行記憶體可能不連續

結論:二維陣列是單一連續區塊;二級指標是指標陣列,每行獨立配置。

完整可執行範例:3×3 矩陣乘法


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void matrix_mult(float (*a)[3], float (*b)[3], float (*c)[3]);
void matrix_init(float (*a)[3]);

float a[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
float b[3][3] = {{2,3,4}, {5,6,7}, {8,9,1}};
float c[3][3] = {{0}};

int main() {
    int i, j;
    
    printf("原始陣列 A:\n");
    for(i=0;i<3;i++) { for(j=0;j<3;j++) printf("%f ", a[i][j]); printf("\n"); }
    
    printf("原始陣列 B:\n");
    for(i=0;i<3;i++) { for(j=0;j<3;j++) printf("%f ", b[i][j]); printf("\n"); }
    
    matrix_init(c);
    matrix_mult(a, b, c);
    
    printf("相乘後陣列 C:\n");
    for(i=0;i<3;i++) { for(j=0;j<3;j++) printf("%f ", c[i][j]); printf("\n"); }
    return 0;
}

void matrix_mult(float (*a)[3], float (*b)[3], float (*c)[3]) {
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
                c[i][j] += a[i][k] * b[k][j];
}

void matrix_init(float (*a)[3]) {
    for(int i=2;i>=0;i--)
        for(int j=2;j>=0;j--)
            a[i][j] = 0;
}

通用解決方案總結

  1. 固定維度:void func(int (*arr)[COLS]) — 最常用、效能最好
  2. 動態維度:void func(int *arr, int rows, int cols) — 手動計算索引 arr[i*cols + j]
  3. 指標陣列:void func(int **arr, int rows) — 需呼叫端建立指標陣列
  4. C99 VLA:void func(int rows, int cols, int arr[rows][cols]) — 編譯器支援可變長度陣列

記憶體模型驗證


int a[10][20];
int *p = &a[0][0];
printf("%zu\n", sizeof(a));   // 800 (10*20*4)
printf("%zu\n", sizeof(p));   // 8 (64位系統指標大小)

這徹底證明:陣列名稱退化為指標時,僅保留基址資訊,型態資訊(維度)丟失,故函數參數必須顯式聲明第二維大小。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性陣列 int a[2]指標 int *p
本質連續記憶體區塊(近似結構體)儲存地址的變數
sizeof8 bytes (2×4)4/8 bytes (指標大小)
可修改性不可修改基址可指向任意位置