8

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?

defectivehalt
  • 2,462
  • 3
  • 21
  • 22

3 Answers3

17

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.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Nice catch with negative or zero size in the declaration, i wouldn't have thought of doing that in the first place. – Georg Fritzsche Feb 16 '10 at 21:31
  • Neat, I didn't know you could enforce the array size. `(*nums)[3]` doesn't work by the way. – defectivehalt Feb 16 '10 at 21:39
  • @Kavon, it does - consider `void f(int (*a)[3]);` vs. `int a[2]; f(&a);`. – Georg Fritzsche Feb 16 '10 at 21:45
  • @Kavon: `int (*nums)[3]` works, but requires some extra work. Within the `printValues()` function, you have to refer to elements as `(*nums)[i]`; and the caller must use an extra `&` as in: `printValues(&buf)` (if `buf` is an array). The idea is that instead of using automatic decay, you make explicit pointers, which keep the type more "intact". It is cumbersome, though. – Thomas Pornin Feb 16 '10 at 21:46
  • &Kavon Farvardin: It does work. You just have to remember that in order to get a pointer to something you need the unary `&` operator and in order to access something through a pointer you need the unary `*` operator. So you have to apply `&` to the argument, and apply `*` to the parameter inside the function: `(*nums)[1]` for example. – AnT stands with Russia Feb 16 '10 at 21:53
3

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
  • 97,545
  • 26
  • 194
  • 236
  • 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. – defectivehalt Feb 16 '10 at 21:29
-2

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
  • 299,747
  • 42
  • 398
  • 622
  • 3
    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. – AnT stands with Russia Feb 16 '10 at 21:14
  • I was under the impression that array size parameters did matter in the case of multidimensional arrays. – Robert Davis Feb 16 '10 at 22:01
  • 2
    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 Feb 16 '10 at 22:21