2011-01-10 90 views

回答

5

它們在功能上是相同的。您應該使用第二種方法並傳遞數組長度爲的參數。

否則,你就是自找麻煩:

// this will compile without warning, even if using -Wall 
int myArray[50] = {0}; 
foo(myArray); 

如果foo()假設數組實際上是100個元素長,它會溢出的陣列。

更好的辦法:

int foo(int *array, size_t array_len) { 
    // do stuff 
} 

更妙的是,使用vector,攜帶它的大小與它可以超越矢量結束不(正常情況下)訪問:

int foo(const std::vector<int>& array) { 
    // do stuff 
} 
+0

...或者您可以傳遞[數組引用](http://stackoverflow.com /問題/ 4650974 /什麼 - 做 - 它 - 平均到具有陣列與 - 大小 - 在功能參數/ 4651412#4651412)。 – 2011-01-11 08:47:02

+0

不錯。我現在避免使用裸露的陣列,所以我不知道這一點。 – Nate 2011-01-11 08:56:24

1

與此聲明無區別

int foo(int array[100]) //1 
int foo(int array[]) //2 
int foo(int *array) //3 

如果函數可以承擔固定大小的數組,在這種情況下,100個元素,1版本更清楚程序員使用此功能。在所有其他情況下 - 3是不錯的選擇

2

沒什麼,他們以相同的方式工作。這裏一個簡單的例子:

int WithArray(int array[10]) 
{ 
    return array[1] + array[2];     // breakpoint 1 
} 

int WithPointer(int *pointer) 
{ 
    return *(pointer + 1) + *(pointer + 2);  // breakpoint 2 
} 

void main() 
{ 
    int array[] = {0,1,2,3,4,5,6,7,8,9}; 

    int b = WithPointer(array); 
    int a = WithArray(array); 

    printf("a = %d\nb = %d\n", a, b); 
} 

好吧,我會先請WithPointer(),以防萬一WIthArray()複製堆棧上的數組。 這裏的所述堆疊中的第二個斷點:

Breakpoint 2, WithPointer (pointer=0xbffff418) at prova.c:10 
10  return *(pointer + 1) + *(pointer + 2); 
(gdb) x/20x ($esp - 8) 
0xbffff404: 0x08049ff4 0xbffff418 0xbffff448 0x0804843b 
0xbffff414: 0xbffff418 0x00000000 0x00000001 0x00000002 
0xbffff424: 0x00000003 0x00000004 0x00000005 0x00000006 
0xbffff434: 0x00000007 0x00000008 0x00000009 0x08048460 
0xbffff444: 0x00000000 0xbffff4c8 0x00144bd6 0x00000001 

正如預期的那樣,有我們的指針(0xbffff418,在第二行的第一個值),並且右後,陣列[](這是對主()」 s堆棧幀)。 讓我們來看看裏面WithArray()堆棧:

(gdb) continue 
Continuing. 

Breakpoint 1, WithArray (array=0xbffff418) at prova.c:5 
5  return array[1] + array[2]; 
(gdb) x/20x ($esp - 8) 
0xbffff404: 0x08049ff4 0xbffff418 0xbffff448 0x08048449 
0xbffff414: 0xbffff418 0x00000000 0x00000001 0x00000002 
0xbffff424: 0x00000003 0x00000004 0x00000005 0x00000006 
0xbffff434: 0x00000007 0x00000008 0x00000009 0x08048460 
0xbffff444: 0x00000003 0xbffff4c8 0x00144bd6 0x00000001 

完全一樣的東西!所以他們如何傳遞給函數沒有區別。並且它們也以相同的方式處理,請看:

(gdb) disass WithPointer 
Dump of assembler code for function WithPointer: 
    0x080483cc <+0>: push %ebp 
    0x080483cd <+1>: mov %esp,%ebp 
    0x080483cf <+3>: mov 0x8(%ebp),%eax   # get base address 
    0x080483d2 <+6>: add $0x4,%eax    # compute offset 
    0x080483d5 <+9>:  mov (%eax),%edx   # dereference and get val. 
    0x080483d7 <+11>: mov 0x8(%ebp),%eax   # base address 
    0x080483da <+14>: add $0x8,%eax    # offset (2 * sizeof(int)) 
    0x080483dd <+17>: mov (%eax),%eax   # get *eax 
    0x080483df <+19>: lea (%edx,%eax,1),%eax  # tricky way to add them 
    0x080483e2 <+22>: pop %ebp 
    0x080483e3 <+23>: ret  
End of assembler dump. 
(gdb) disass WithArray 
Dump of assembler code for function WithArray: 
    0x080483b4 <+0>:  push %ebp 
    0x080483b5 <+1>:  mov %esp,%ebp 
    0x080483b7 <+3>:  mov 0x8(%ebp),%eax   # first element of array 
    0x080483ba <+6>:  add $0x4,%eax    # move to the second 
    0x080483bd <+9>:  mov (%eax),%edx   # and get its value 
    0x080483bf <+11>: mov 0x8(%ebp),%eax   # base of array 
    0x080483c2 <+14>: add $0x8,%eax    # compute address of second 
    0x080483c5 <+17>: mov (%eax),%eax   # element and get load it 
    0x080483c7 <+19>: lea (%edx,%eax,1),%eax  # compute sum 
    0x080483ca <+22>: pop %ebp 
    0x080483cb <+23>: ret  
End of assembler dump. 

代碼是相同的。請注意,該數組是作爲指針處理的。

3

在C++中,不能將數組作爲參數傳遞給函數。根據§8.3.5至pointer to T轉換展示array of T類型參數的函數聲明。這意味着下面的聲明是完全等價的:

void f(int a[10]); 
void f(int a[]); 
void f(int *a); 

所以,事實上,正如你指出他們是完全等價的,即使第一個可能會誤導開發商閱讀代碼的編譯器,作爲給定大小在聲明中不會被強制執行。

這是爲了那些reference to array of T類型,其中說法也不衰減的指針的函數參數的不同,而是保持了完整的類型:

void f(int (&a)[10]); // takes an array of exactly 10 integers 

在這種情況下,編譯器將實際強制執行引用的類型,即array of 10 int(包括大小)。函數內部的代碼可以假設總是有10個元素,編譯器會確保這一點。

§8.3.5[dcl.fct]/3

[...]確定每個參數的類型,類型的任何參數「陣列T的」或後「函數返回T」是調整爲「指向T的指針」或「指向函數返回T的指針」。[...]