只見那看起來是這樣的是什麼意思有陣列與功能尺寸參數
int foo(int array[100])
{
...
}
的功能是如何從
int foo(int *array)
此不同的是,它有什麼不同?
在哪些地方應該/可以使用前一種方法。
只見那看起來是這樣的是什麼意思有陣列與功能尺寸參數
int foo(int array[100])
{
...
}
的功能是如何從
int foo(int *array)
此不同的是,它有什麼不同?
在哪些地方應該/可以使用前一種方法。
它們在功能上是相同的。您應該使用第二種方法並傳遞數組長度爲的參數。
否則,你就是自找麻煩:
// 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
}
與此聲明無區別
int foo(int array[100]) //1
int foo(int array[]) //2
int foo(int *array) //3
如果函數可以承擔固定大小的數組,在這種情況下,100個元素,1版本更清楚程序員使用此功能。在所有其他情況下 - 3是不錯的選擇
沒什麼,他們以相同的方式工作。這裏一個簡單的例子:
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.
代碼是相同的。請注意,該數組是作爲指針處理的。
在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的指針」。[...]
...或者您可以傳遞[數組引用](http://stackoverflow.com /問題/ 4650974 /什麼 - 做 - 它 - 平均到具有陣列與 - 大小 - 在功能參數/ 4651412#4651412)。 – 2011-01-11 08:47:02
不錯。我現在避免使用裸露的陣列,所以我不知道這一點。 – Nate 2011-01-11 08:56:24