我看到一个看起来像这样的函数
int foo(int array[100])
{
...
}
与
有什么不同int foo(int *array)
不同吗?
我们应该/可以使用前一种方法。
答案 0 :(得分: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
}
答案 1 :(得分:3)
在C ++中,您不能将数组作为参数传递给函数。根据§8.3.5到array of T
,将表示类型为pointer to 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 of T”或“函数返回T”的参数都被调整为“指向T的指针”或“指向函数返回T的指针”, 。[...]
答案 2 :(得分: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,第二行的第一个值),然后就是array [](在main(的)堆栈帧上)。 让我们检查一下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 :(得分:1)
与此声明没有区别
int foo(int array[100]) //1
int foo(int array[]) //2
int foo(int *array) //3
如果函数只能采用固定大小的数组,在这种情况下100个元素,1个版本对使用此函数的程序员更清楚。在所有其他情况下 - 3是不错的选择