5

I know that when I want to pass an array to a function, it will decay into pointer, so its size won't be known and these two declarations are equivalent:

void funtion(int *tab, int size);

and

void funtion(int tab[], int size);

And I understand why. However, I checked that when I pass an array as a reference:

void funtion(int (&tab)[4]);

the compiler will know the size of the array and won't let me pass an array of different size as an argument of this function.

Why is that? I know that when I pass an array by address, the size isn't taken into account while computing the position of the ith element in the array, so it is discarded even if I explicitly include it in the function declaration:

void funtion(int tab[4], int size);

But what is different when I pass an array by reference? Why is its size known to the compiler?

Note: I'm interested in arrays whose size is known at compile time, so I didn't use any templates.

I found a similar question on Stack Overflow, however it doesn't answer my question - it doesn't explain why the compiler knows the size of the array, there is just some information on how to pass arrays to functions.

Community
  • 1
  • 1
user2738748
  • 1,106
  • 2
  • 19
  • 36

3 Answers3

6

Because it can, and because checking adds extra safety. The compiler knows the size of the array because you tell it so, right there in the function declaration. And since that information is available, why wouldn't it use it to signal errors in your source code?

The real question is why your last example wouldn't do the same check. This is, unfortunately, another piece of C legacy - you are never passing an array, it always decays into a pointer. The size of the array then becomes irrelevant.

Could a check be added? Possibly, but it would be of limited use (since we are all using std::array now - right!?), and because it would undoubtedly break some code. This, for example:

void func (char Values [4]);
func ("x");

This is currently legal, but wouldn't be with an additional check on array size.

H. Guijt
  • 3,325
  • 11
  • 16
  • Thanks:) It probably is a stupid question, but why doesn't an array passed by reference decay into a pointer? And why would adding a check break some code assuming it works well now? – user2738748 Mar 10 '16 at 17:46
  • 3
    @user2738748 Decaying to pointer is a terrible legacy of C. No one likes it, but it it is hard to change it in C++, since there is a certain desire to make as much C code compilable with C++ compiler as possible. But since there are no references in C, C++ can set any rules regarding them, unbound. And the sane rules were set. – SergeyA Mar 10 '16 at 17:49
0

Because there is no odd implicit type change committed by the compiler in the case. Normally when you write:

void func(int[4]);

or

void func(void());

The compiler decides to "help" you and translates those into:

void func(int *);

or

void func(void(*)());

Funny thing though - it wouldn't aid you in such a way when you try returning one of those. Try writing:

int func()[4], func1()();

Ooops - surprise - compiler error.

Otherwise arrays are arrays and have constant size which can be acquired by using the sizeof operator.

This however is often forgotten because of the compiler behavior noted above and also because of the implicit pointer conversion applied to objects of array type when such isn't expected. And this is very often. Though here are the few exceptions when no implicit array object conversion is applied:

size_t arr[4], 

    (*parr)[3] = &arr, //taking the address of array

    (&refarr)[3] = arr, //storing reference to array

    sizearrobject = sizeof(arr); //taking the array object size

The above examples will trigger compiler error because of incompatible types on the second and third line.

I'm talking about the cases when arr object isn't automatically converted to something like this:

(size_t*)&arr
AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
0

Well, there are several ways to pass an array to function. You can pass it by pointer an by reference, and there are ways to define or not to define it's size explicitely for both ways.


In your question you compare these 2 ways:
  • Pointer to first element: void f(int *arr)
  • Reference to an entire array: void f(int (&arr)[size])

You ask why you need to specify size only in one of these cases.

It looks like you assume that the only difference between them is the fact that one uses pointer and another uses reference. But this statement is incorrect, they have more differences: One is pointer to first element, but second is a reference to an entire array.


You can pass an array by pointer to an entire array:
void f(int (*arr)[size])

Compare it with your example, with passing by refence to an entire array:

void f(int (&arr)[size])    

They are similar, they have similar syntax, they both explicitely define array size.


Also, consider this:
void f(int &arr)

It looks like passing a single int by reference, but you can pass an array of unknown size to it.

Pointer alternative to it is

void f(int *arr)

You ask why you need to specify array size only in one of those cases. It's because of the syntax you used, not because one is pointer and other is reference.

As I said, you can use pointer or reference. And you can specify array size or you can allow an array of any size to be used. These two are not connected.

//                     by pointer             by reference
/*   Any size    */    void f(int *arr)       void f(int &arr)
/* Specific size */    void f(int (*arr)[x])  void f(int (&arr)[x])
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207