2012-04-01 66 views
7

考慮代碼:傳遞給函數而不是常量指針的數組參數?

void foo(char a[]){ 
    a++;   // works fine, gets compiled 
    //... 
} 

現在,考慮一下:

void foo(){ 
    char a[50]; 
    a++;   // Compiler error 
    //... 
} 

我聽到一個陣列相當於一個常量指針,不能增加,因爲它不是一個左值...

那麼爲什麼第一個代碼被編譯,是這樣,因爲函數的數組參數作爲指針傳遞,即T []轉換爲T *傳遞..因此,foo(a)傳遞一個作爲指針。

但是,它不迴轉換爲T []再次因爲被聲明爲:

void foo(char a[]); 
+2

閱讀[comp.lang.c常見問題](http://c-faq.com)的第6部分。 – 2012-04-01 09:54:03

回答

13

當傳遞數組作爲參數傳遞給一個函數,它衰減至一個指針。
所以你的函數體內增加的東西是一個指針,而不是一個數組。

+0

特別是,您好像宣佈'char * temp = a;'然後遞增'temp'。 – 2012-04-01 23:15:40

4

我聽到一個陣列相當於一個常量指針

可以認爲這樣的說法,但他們不等價的。

數組傳遞給函數時衰減到指針,這就是爲什麼在函數內部它是有效的。

只是因爲簽名void foo(char a[])不作a數組。

功能之外,它只是一個數組,你不能做就可以了指針算術。

1

當傳遞一個數組a []於函數時,它通過「A」,地址的值到函數。所以你可以使用它作爲函數中的指針。如果你在函數中聲明瞭一個數組,'a'是恆定的,因爲你不能在內存中改變它的地址。

8

這是一個從C語言繼承而來的相當不幸的特徵,它的名字相當邪惡。由於C曾經不允許按值傳遞複合類型,因此他們決定允許程序員將數組指定爲函數參數類型,但僅在美觀方面。陣列型衰減到指針類型,從語言的其餘部分執行一種通過按引用語義不同的。醜陋。

回顧一下(和其他人已經說過這一點),簽名

void foo(char a[]); // asking for trouble 

被毫不客氣地錯位到

void foo(char *a); 

...所有兼容性的緣故,與古老的C代碼。既然你不寫古代的C代碼,你不應該利用這個「特性」。

但是,您可以乾淨地將參考傳遞給一個數組。C++要求數組的大小被稱爲:

void foo(char (&a)[ 50 ]); 

現在a不能在函數內部修改(編輯:其內容當然可以 - 你明白我的意思),而唯一的陣列正確的大小可以通過。對於其他事情,傳遞一個指針或更高級別的類型。

-1

函數內部,a是一個地址本身,它指向一個局部變量。你可以增加它,因爲它是一個地址。你也可以這樣做:

char a[50]; 
int i; 
for(i=0;i<50;i++) 
    *(a+i)='b'; 

沒有錯誤。

+2

不,數組沒有傳遞給函數,只有它的第一個元素的地址。 – 2012-04-01 09:55:38

+0

我不這麼認爲。在第一種類型中,我的意思是'void foo(char [] a){..}',數組中的更改不會影響函數返回的主數組。 – mtyurt 2012-04-01 10:26:49

+1

更改'a'隻影響參數,它是一個本地*指針*對象。嘗試修改'a [0]'看看會發生什麼。然後閱讀[comp.lang.c FAQ](http://c-faq.com)的第6部分。 – 2012-04-01 15:37:21

3

在C++中,類型爲「T的數組」的任何函數參數被調整爲「指向T的指針」。試試這個代碼:

void foo(char a[]) {} 
void foo(char* a) {} //error: redefinition 

它們確實是一樣的功能。

那麼,爲什麼我們可以將一個數組參數作爲指針參數傳遞給一個函數呢?不是因爲數組相當於一個常量指針,而是因爲數組類型可以隱式轉換爲指針類型的右值。還要注意轉換的結果是一個右值,這就是爲什麼你不能將運算符++應用於數組,所以你只能將這個運算符應用於左值。

1

聽說的陣列相當於一個恆定指針,並且不能增加,因爲它不是一個左值...

幾乎。

An array expression is non-modifiable lvalue;它可能不是運算符的操作數,如++--,它可能不是賦值表達式的目標。這與常量指針不同(即聲明爲T * const的指針)。

數組表達將用指針表達式,其值是數組的除第一元件的地址替換當陣列表達是sizeof或一元&運營商的操作數,或當陣列表達是一個字符串文字用於在聲明中初始化另一個數組。

當調用以與陣列參數的函數,如

int a[N]; 
... 
foo(a); 

表達a從型「int N元件陣列」到「指針int」而該指針值轉換是什麼傳遞給foo;因此,相應的函數原型應該是

void foo (int *arr) {...} 

。注意,在一個功能參數聲明,T a[]T a[N]是相同的T *a的上下文中在所有三種情況下,a被聲明爲指向T。在函數foo內,參數arr是指針表達式,其中可修改的左值,並且因此它可以被分配給並且可以是運算符的操作數和++--運算符。

請記住,所有這些轉換都在表達式上;即數組標識符或其他表達式引用內存中的數組對象。數組對象(包含數組值的內存塊)未被轉換。