2010-01-09 60 views
6

,當我需要一個數組傳遞給一個函數,似乎所有的功能的以下聲明將工作數組類型 - 規則的函數參數分配/使用

void f(int arr[]) 
void f(int arr[4]) // is this one correct? 

此:

int a[]={1,2,3,4}; 
f(a); 

但是當我分配一個陣列到另一個陣列,它失敗

int a[]={1,2,3,4}; 
int b[4] = a; // error: array must be initialized with a brace-enclosed initializer 

那麼,爲什麼數組作爲argum傳遞一個函數的入口是可以的,但用於簡單賦值的rhs是錯誤的?

+3

問題的標題需要重寫,當前的標題是過於通用和小寫。 – 2010-01-10 04:34:47

回答

12

對於理解不同,我們需要了解兩種不同上下文

  • 上下文,T類型的數組的名稱是相當於一個指針鍵入T,並等於一個指針數組的第一個元素。
  • 對象上下文中,類型爲T的數組的名稱不會減少爲指針。

什麼是對象上下文?

a = b;,a處於對象上下文中。當你獲取一個變量的地址時,它用在對象上下文中。最後,在變量上使用sizeof運算符時,它在對象上下文中使用。在所有其他情況下,在值上下文中使用一個變量。

現在,我們有這方面的知識,當我們這樣做:

void f(int arr[4]); 

這是正是相當於

void f(int *arr); 

當你發現了,我們可以省略(以上4)大小來自函數聲明。這意味着你無法知道傳遞給f()的「數組」的大小。後來,當你這樣做:

int a[]={1,2,3,4}; 
f(a); 

在函數調用,這個名字a是在價值方面,所以它減少的指針int。這很好,因爲f需要一個指向int的指針,所以函數定義和使用匹配。傳遞給f()的是指向a&a[0])的第一個元素的指針。

int a[]={1,2,3,4}; 
int b[4] = a; 

名稱b的情況下在一個對象上下文中使用,並且不降低到指針。 (順便說一下,這裏a處於值上下文,並減少了一個指針。)

現在,int b[4];分配的4個int S吸留值得並給出了名稱b給它。 a也被分配了類似的存儲空間。所以,實際上,上述分配意味着「我想使存儲位置與先前的位置相同」。這沒有意義。

如果你想副本a內容爲b,那麼你可以做:

#include <string.h> 
int b[4]; 
memcpy(b, a, sizeof b); 

或者,如果你想要一個指針b是指向a

int *b = a; 

這裏,a在值上下文中,並且減少到指向int的指針,所以我們可以將a分配給一個int *

最後,初始化數組時,可以分配給它明確的價值觀:

int a[] = {1, 2, 3, 4}; 

這裏,有4個元素,初始化爲1,2,3和4。你也可以做:

int a[4] = {1, 2, 3, 4}; 

如果在列表中比陣列中元件的數量較少的元素,則這些值的其餘部分被取爲0:

int a[4] = {1, 2}; 

a[2]a[3]爲0

+0

編寫得很好。 – benzado 2010-01-09 23:35:08

+0

你能提供一個關於對象和值上下文的閱讀地點的參考嗎? – 2011-12-23 13:57:02

+0

我從來沒有聽說過「物體背景」與「價值背景」 – 2011-12-23 14:02:16

7
void f(int arr[]); 
void f(int arr[4]); 

該語法具有誤導性。它們都與此相同:

void f(int *arr); 

即,您傳遞的是指向數組的開始的指針。您不復制陣列。

+3

是的,但是(在C99中)'void f(int arr [static 4]){...}' 是特殊的,因爲這允許編譯器假定'arr'不是'NULL'並且其大小至少4. – Jed 2010-01-09 21:55:33

6

C不支持數組的賦值。在函數調用的情況下,數組衰減爲指針。 C支持指針的分配。這裏幾乎每天都會問到這個問題 - 你們讀的C文本書不能解釋這一點嗎?

3

嘗試使用memcpy。

int a[]={1,2,3,4}; 
int b[4]; 
memcpy(b, a, sizeof(b)); 

感謝您指出了這一點,史蒂夫,它已經有一段時間,因爲我用C.

+1

'memcpy(b,a,4 * sizeof(int)'。或'sizeof(b)'。 – 2010-01-09 22:31:20

1

爲了讓你的直覺的話,你必須明白這是怎麼回事機器水平。

初始化語義(= {1,2,3,4})意思是「把它放在你的二進制圖像上」,所以這可以編譯。

數組賦值可能會有所不同:編譯器必須將其轉換爲循環,實際上將在元素上迭代。 C編譯器(或C++,就此而言)從未做過這樣的事情。它理所當然地希望你自己去做。爲什麼?因爲你能。所以,它應該是一個用C(memcpy)編寫的子程序。這一切都是關於簡單和親近你的武器,這是C和C++的全部。

0

請注意,int a[4]a的類型爲int [4]

TypeOf運算&a)== int (*)[4]!= int [4]

還請注意,a的類型是int *,它與以上所有不同!

下面是一個示例程序,你可以嘗試一下:我想澄清

int main() { 
    // All of these are different, incompatible types!  
    printf("%d\n", sizeof (int[4])); // 16 
    // These two may be the same size, but are *not* interchangeable! 
    printf("%d\n", sizeof (int (*)[4])); // 4 
    printf("%d\n", sizeof (int *)); // 4 
} 
+0

您應該使用「%zu」打印size_t(在C99中)。 – Jens 2011-04-17 07:43:16

0

。有在回答一些誤導性的提示...所有下列功能可以採取整數數組:

void f(int arr[]) 
void f(int arr[4]) 
void f(int *arr) 

形式參數是不一樣的。所以編譯器可以以不同的方式處理在內部內存管理的意義上,所有的爭論都會導致指針。

void f(int arr[]) 

... f()取任意大小的數組。

void f(int arr[4]) 

...正式參數表示數組大小。

void f(int *arr) 

...您也可以傳遞一個整數指針。 f()不知道有關的大小。

相關問題