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

揭開 C/C++ 數組形參迷霧:數組退化、指針等價與引用傳遞真相

     編輯:關於C++

楔子

早前周星星大哥發文「用數組引用避免數組降階」,當時未深悟。如今重讀,結合四大核心問題逐層剖析,終得真諦。本文從形參實參關係、數組名指針關係、引用本質、聲明表達式解析四維入手,徹底講透數組形參傳遞機制。

一、形參與實參:賦值關係

void Foo(int a); Foo(10); 實參 10 傳給形參 a,本質是 賦值過程(a=10)。所有類型同理,可在 VC 中調試驗證。

二、數組名與指針:表達式中等價,聲明中不同

C 標準規定:表達式中數組名轉換為指向首元素的指針;函數參數聲明中數組名調整為指針。因此:

void Foo1(int arr[100]) {}
void Foo2(int arr[]) {}
void Foo3(int *arr) {}
// 三者完全等效

但聲明處不同:int a[100]; int *b; — sizeof(a)=400,sizeof(b)=4。數組名在 sizeof 中不轉換,保留完整類型信息。

三、引用本質:惡鬼附體,密不可分

引用一經定義即綁定目標,對引用的任何操作直接反映在被引用變量上,不像指針只是訪問方式。驗證代碼:

int a=10; int &a_ref=a; int b=20; int &b_ref=b;
a_ref = b_ref; // 實為 b 賦值給 a,a_ref 仍綁定 a
cout << a_ref << " " << b_ref; // 20 20
cout << a << " " << b;         // 20 20
int *p=&a, *q=&a_ref; // p==q,取引用地址得被引用變量地址
// 指針可改指向:p=&a; q=&b; p=q; // p,q 同指 b,a 不變

運行結果證明:引用「惡鬼附體」,指針「可換目標」。

四、聲明即表達式:運算符優先級解析法

分析 int (&arr)[100]:

  1. 找聲明符 arr
  2. &arr → 引用
  3. (&arr)[100] → 100 元素數組
  4. int → 元素類型
  5. 結論:arr 是「含 100 個 int 的數組的引用」

用 typedef 化繁為簡:typedef int INTARR[100]; void Foo(INTARR &arr) {} 瞬間明瞭。

大結局:還原最初的 Demo

int a[100];
int *pa = a;
int (&a_ref)[100] = a;
sizeof(a)   // 400,數組完整類型
sizeof(pa)  // 4,指針大小
sizeof(a_ref) // 400,引用即數組本體

函數傳遞即賦值:
Foo1(a) → 形參 int arr[100] 調整為 int*,實際傳 &a[0],sizeof(arr)=4。
Foo2(a) → 形參 int (&arr)[100],引用綁定數組,sizeof(arr)=400。
並非函數把數組「降階」,而是聲明機制決定:指針形參丟失長度,引用形參保留長度。

C 語言無引用時的替代方案

  1. 額外參數傳長度: main(int argc, char** argv),防溢出,安全性高。
  2. 哨兵值標記結束: C 字符串以 '\0' 結尾,無長度限制(變量長度受類型限制,如 unsigned byte 限 256)。
  3. 多維數組用特殊行作哨兵: a[3][3] = {{...}, {...}, {-1,-1,-1}},遇全 -1 行知結束。

方法靈活多變,關鍵在人。丹尼斯·里奇曾言:「C 詭異離奇,缺陷重重,卻獲得巨大成功。」

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