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

C 語言陣列作為函數參數:值傳遞、位址傳遞與實戰陷阱

     編輯:關於C語言

兩種傳遞形式

  1. 陣列元素(下標變數)作實參:本質是標量值傳遞,與普通變數無異。
  2. 陣列名作參數:實際傳遞首元素位址,形參與實參共享同一記憶體區塊。

形式一:陣列元素作實參 —— 純值傳遞


void nzp(int v) {          // 形參為標量
    if (v > 0) printf("%d ", v);
    else printf("%d ", 0);
}

int main() {
    int a[5];
    for (int i = 0; i < 5; i++) {
        scanf("%d", &a[i]);
        nzp(a[i]);           // 傳遞 a[i] 的值
    }
}
  • 每次呼叫複製一個 int 值,函數內修改不影響原陣列。
  • 適合唯讀、逐元素處理場景。

形式二:陣列名作參數 —— 位址傳遞(模擬引用)

記憶體模型

實參陣列 a:位址 2000 起,佔 10 bytes (5 int)
形參陣列 b:無獨立記憶體,b 即為指標指向 2000
a[i] 與 b[i] 物理上為同一記憶體單元

語法三種等價寫法


float aver(float a[5]) { ... }      // 帶長度(僅文檔用,編譯器忽略)
float aver(float a[]) { ... }       // 空括號
float aver(float *a) { ... }        // 指標形式(本質相同)

編譯器均視為 float *a,不檢查長度,長度資訊丟失,需額外參數傳遞。

範例:計算平均分


float aver(float a[5]) {
    float s = 0;
    for (int i = 0; i < 5; i++) s += a[i];
    return s / 5;
}

int main() {
    float sco[5];
    for (int i = 0; i < 5; i++) scanf("%f", &sco[i]);
    printf("%.2f", aver(sco));  // sco 退化為指標傳遞
}

關鍵差異:雙向影響


void nzp(int a[5]) {
    for (int i = 0; i < 5; i++)
        if (a[i] < 0) a[i] = 0;   // 修改形參陣列
}

int main() {
    int b[5] = {10, -2, 5, -1, 8};
    nzp(b);                       // 實參 b 被修改!
    // b 現在為 {10, 0, 5, 0, 8}
}
  • 形參修改直接反映到實參,因共用記憶體。
  • 這不是「雙向值傳遞」,而是同一物件的別名。
  • 若需保護原陣列,函數內應複製陣列或標記 const:void nzp(const int a[5])。

多維陣列傳遞


// 二維陣列:必須指定第二維長度
void print(int a[][4], int rows) { ... }
void print(int (*a)[4], int rows) { ... }  // 指向含 4 int 陣列的指標

int main() {
    int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    print(a, 3);
}
  • 一維陣列退化為指標,二維陣列退化為指向陣列的指標(int (*)[4]),非 int **。
  • 記憶體連續佈局:a[0][0], a[0][1]... a[1][0]...

常見錯誤與避坑指南

錯誤代碼問題修正
void f(int a[10]) { sizeof(a); }sizeof(a) 為指標大小 (4/8),非陣列大小額外傳長度參數
int a[10]; f(&a);類型不匹配:&a 為 int (*)[10]直接傳 a
void f(int **a) { ... } 接收二維陣列二維陣列非指標陣列用 int (*a)[N] 或扁平化一維陣列
形參未加 const 導致誤改實參副作用難追蹤唯讀陣列加 const

現代 C 最佳實務

  1. 總是傳遞長度:void process(int *arr, size_t len)。
  2. 唯讀加 const:void print(const int *arr, size_t len)。
  3. 避免陣列參數語法,直接寫指標:int *arr 語意更清晰。
  4. C99 可變長度陣列 (VLA):void f(int n, int a[n]) 保留長度資訊(但棧分配風險大,慎用)。
  5. 結構體封裝:struct Vec { int *data; size_t len; } 實現帶長度的陣列物件。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved