在函数参数中使用大小的数组意味着什么

时间:2011-01-10 20:06:09

标签: c++ arrays

我看到一个看起来像这样的函数

int foo(int array[100])
{
...
}

有什么不同
int foo(int *array)

不同吗?

我们应该/可以使用前一种方法。

4 个答案:

答案 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是不错的选择