views:

160

answers:

3

I don't understand why the following example compiles and works:

void printValues(int nums[3], int length) {
    for(int i = 0; i < length; i++) 
        std::cout << nums[i] << " ";
    std::cout << '\n';
}

It seems that the size of 3 is completely ignored but putting an invalid size results in a compile error. What is going on here?

A: 

The size of the array is not ignored, it is part of the type of the argument. You should get a compiler error if you try to pass an array of any other size into the function.

On the other hand C and C++ don't do bounds checking on array accesses, so in that sense they are ignored. But that's true in any other context as well, not just for function parameters.

Mark Ransom
Not true. In the above declaration, the array size is a part of the syntax, but it has no semantic effect. The parameter declaration is equivalent to `int nums[]` and to `int *nums`. Size is indeed ignored.
AndreyT
@AndreyT: Really? Learn something new every day - I must try that sometime to see for myself.
Mark Ransom
I was under the impression that array size parameters did matter in the case of multidimensional arrays.
Robert Davis
When you pass a multidimensional array, then it probably decays to passing a pointer to array (with one less dimension) - hence the size of all but the first dimension matters.
UncleBens
+2  A: 

I don't see what compile error you are referring to - arrays passed to a function decay to pointers and you lose the array type information. You might as well have used:

void printValues(int* nums, int length);

You can avoid the decay to pointers by using references:

void printValues(int (&nums)[3], int length);

Or simply use pointers if you don't want fixed-sized arrays.

Georg Fritzsche
At least with the Visual C++ compiler, it will throw an error if the array's size is <= 0 even if the value will be entirely ignored anyway.
Kavon Farvardin
+4  A: 

In C++ (as well as in C), parameters declared with array type always immediately decay to pointer type. The following three declarations are equivalent

void printValues(int nums[3], int length);
void printValues(int nums[], int length);
void printValues(int *nums, int length);

I.e. the size does not matter. Yet, it still does not mean that you can use an invalid array declaration there, i.e. it is illegal to specify a negative or zero size, for example.

(BTW, the same applies to parameters of function type - it immediately decays to pointer-to-function type.)

If you want to enforce array size matching between arguments and parameters, use pointer- or reference-to-array types in parameter declarations

void printValues(int (&nums)[3]);
void printValues(int (*nums)[3]);

Of course, in this case the size will become a compile-time constant and there's no point of passing length anymore.

AndreyT
Nice catch with negative or zero size in the declaration, i wouldn't have thought of doing that in the first place.
Georg Fritzsche
Neat, I didn't know you could enforce the array size. `(*nums)[3]` doesn't work by the way.
Kavon Farvardin
@Kavon, it does - consider `void f(int (*a)[3]);` vs. `int a[2]; f(`.
Georg Fritzsche
Thomas Pornin
AndreyT
Kavon Farvardin