C 陣列作為引數傳遞的那些事兒

2021-08-17 03:24:20 字數 2102 閱讀 9170

先看**:

#include 

void foo(int

array[2])

void bar(int

array)

void baz(int (&array)[2])

int main()

; printf("main::a[2]:\t\t%x %d\n", a, sizeof(a));

foo(a);

bar(a);

baz(a);

return

0;}

輸出:

main::a[2]:             28feb8 8

intarray[2]: 28fea0 4

intarray: 28fea0 4

int (&array)[2]: 28feb8 8

解說:

foo和bar的傳值方式是相同的,都是乙個int*, 即乙個整型指標,這可以從foo和bar裡列印出的array位址和main中的不同和sizeof(array)僅為sizeof(int*)看出,只不過是外型有點兒區別。

編譯器是不知道你要傳遞的是乙個陣列或是單一乙個整型的位址的,這是因為c中陣列的記憶體模型是連續儲存(它並不知道傳遞的(首)位址之後的空間可否訪問)。

所以寫為foo或bar的樣式僅僅是對人的一種暗示,暗示傳遞的是乙個陣列,括號裡的2編譯器是不會把他當回事兒的①。

採用foo中的樣式,**編寫者在函式中獲知傳遞的陣列的大小,但這種暗示功能很弱,而且易使人產生誤解。

比如以上的函式foo,傳遞大小為1個元素的陣列(即單一乙個整型的位址):

int x[1];

foo(x);

或傳遞乙個大小為100的陣列:

int x[100];

foo(x);

編譯器都不會有任何抱怨,所以在**工程量很大的時候,你無法保證陣列傳值的安全性,另外乙個問題是如果你寫的是商業性質的庫,你無法保證客戶(二次開發者)能安全地使用你的**。

採用bar中樣式,實質和foo相同,空括號給人的暗示就是它能接受的引數是乙個陣列,而且是乙個長度不確定的一維整型陣列,這相對於foo來說更為實際和真實一些(因為foo可能造成欺騙性的**,原因見上)。

所以這種傳陣列的方式被多數人所採用,但一般還需多加乙個引數來指定陣列的大小,如:

void bar(int array, int size);

或效仿stl的做法,傳遞陣列的首位址和超尾指標(在遍歷陣列元素時很方便,且更快速、安全):

void bar(int* beg, int* end);

至於baz,它不同於foo和bar。前面已經說過,foo和bar實質是相同的,傳的都是乙個int*,且傳值方式都是按值傳遞(c中只有按值傳遞)。

而baz卻是按引用傳遞,傳遞的是乙個」編譯器認可的,大小為2」②的陣列的引用。

foo和bar都可以改寫為:

void thefact(int* array);

或 void thefact(int* array, int size);

按照此邏輯是不是baz可改寫為這樣呢?

void baz2(int* const& array); // a其實是乙個int* const型指標,所以要加上const作為修飾

答案是否定的,注意上面的②,只有在c++中,函式」按引用」傳遞陣列並」指定其大小時」,中的數字才有意義(對編譯器而言)。所以baz2 != baz:

int x[100];

baz(x); // 編譯錯誤

baz2(x); // 可以通過

要理解這和foo, bar的不同首先要理解c++中對引用的定義: 引用就是物件本身,不存在沒有引用物件的引用。所以在baz中,形參array就是實參main中的a,一切a所有的特性都是array的特性,所以sizeof(array) == sizeof(a),而且&baz::array == main::a(位址相同)。

①: c99中允許使用static陣列引數修飾詞,如:

void foo(int x[static 10]); // x陣列至少含有10個連續元素

上句中的10此時並不是可有可無的,它是編譯器優化陣列訪問的一種暗示。

陣列作為函式引數傳遞

陣列有兩個特殊的性質。一是不能複製陣列 二是使用陣列名字時,陣列會自動轉化為指向其第乙個元素的指標。由於陣列不能複製,所以無法編寫使用陣列型別形參的函式,因為陣列會被自動轉化為指標。一 一維陣列 1.三種定義形式 void printvalues int void printvalues int v...

陣列作為函式引數傳遞

重點 在c中,陣列是不能作為引數進行傳遞的,但是可以通過傳遞指向陣列初始元素的指標,使得在函式內部運算元組成為可能。在函式這一側,可以通過array i 引用陣列的內容。why?本質上array i 不過是 array i 的語法糖。include void func int array,int s...

使用陣列作為引數傳遞

如果乙個函式以一維陣列為引數,我們可以這樣宣告這個函式 void func int a void func int a void func int a 3 實際上,這三種形式是等價的,在使用陣列做引數時,編譯器會自動將陣列名轉換為指向陣列第乙個元素的指標,為什麼呢?這要從引數的傳遞方式說起,引數有三...