开发者

What does it mean to have array with size in function parameters

I saw a function that looked something like this

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

how is this 开发者_C百科different from

int foo(int *array)

Is it different?

In what places should/can we use the former method.


They are functionally the same. You should use the second method and pass a parameter for the length of the array.

Otherwise, you are asking for trouble:

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

If foo() assumes that the array is actually 100 elements long, it will overrun the array.

Better way:

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

Even better, use a vector, which carries its size with it and you cannot (under normal circumstances) access beyond the end of the vector:

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


In C++, you cannot pass an array as an argument to a function. A function declaration that exhibits a parameter of type array of T is converted, according to §8.3.5 to pointer to T. This means that the following declarations are exactly equivalent:

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

So in fact, as you point out they are exactly equivalent for the compiler even if the first one might be misleading to developers reading the code, as the given size in the declaration will not be enforced.

This is different to function parameters that are of type reference to array of T, where the argument does not decay to a pointer, but rather keeps the full type:

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

In this case, the compiler will actually enforce the type of the reference, which is array of 10 int (including size). The code inside the function can assume that there will always be 10 elements, and the compiler will ensure that.

§8.3.5 [dcl.fct] /3

[...]After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively.[...]


Nothing, they work in the same way. Here a short example:

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);
}

Ok, I'll call WithPointer() first, just in case WIthArray() copies the array on the stack. Here's the stack at the second breakpoint:

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

As expected, there's our pointer (0xbffff418, the first value on the second line) and, right after that, array[] (which is on main()'s stack frame). Let's check the stack inside 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

Exactly the same thing! So there's no difference about how they're passed to functions. And they're handled in the same way too, look:

(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.

Codes are identical. Note that the array is handled as a pointer.


No difference with this declaration

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

If function can take only fixed sized array, in this case 100 elements, 1 version are more clear to programer which use this function. In all other cases - 3 are good choice

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜