259

How does passing a statically allocated array by reference work?

void foo(int (&myArray)[100])
{
}

int main()
{
    int a[100];
    foo(a);
}

Does (&myArray)[100] have any meaning or its just a syntax to pass any array by reference? I don't understand separate parenthesis followed by big brackets here. Thanks.

Sean Bone
  • 3,368
  • 7
  • 31
  • 47
John DB
  • 2,591
  • 3
  • 15
  • 3

5 Answers5

306

It's a syntax for array references - you need to use (&array) to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references int & array[100];.

EDIT: Some clarification.

void foo(int * x);
void foo(int x[100]);
void foo(int x[]);

These three are different ways of declaring the same function. They're all treated as taking an int * parameter, you can pass any size array to them.

void foo(int (&x)[100]);

This only accepts arrays of 100 integers. You can safely use sizeof on x

void foo(int & x[100]); // error

This is parsed as an "array of references" - which isn't legal.

Erik
  • 88,732
  • 13
  • 198
  • 189
  • Why can't we have an array of references e.g. `int a, b, c; int arr[3] = {a, b, c};`? – Vorac Jan 07 '16 at 13:10
  • 10
    Aha, found out [why](http://stackoverflow.com/questions/1164266/why-arrays-of-references-are-illegal#1164306). – Vorac Jan 08 '16 at 13:51
  • 2
    Could someone explain why `void foo(int & x[100]);` is parsed as "array of references" please? Is it because the "from-right-to-left" rule? If yes, it seems to be not consistent with how `void foo(int (&x)[100]);` is parsed as "a reference to a array". Thanks in advance. – zl9394 Feb 11 '17 at 00:52
  • 7
    It's not right to left, it's inside out, and [] binds tighter than &. – philipxy May 06 '17 at 03:10
  • 1
    "This only accepts arrays of 100 integers. You can safely use sizeof on x" is a good clarification to mention. – Erik Sep 22 '22 at 08:04
71

It's just the required syntax:

void Func(int (&myArray)[100])

^ Pass array of 100 int by reference the parameters name is myArray;

void Func(int* myArray)

^ Pass an array. Array decays to a pointer. Thus you lose size information.

void Func(int (*myFunc)(double))

^ Pass a function pointer. The function returns an int and takes a double. The parameter name is myFunc.

Nayuki
  • 17,911
  • 6
  • 53
  • 80
Martin York
  • 257,169
  • 86
  • 333
  • 562
32

It is a syntax. In the function arguments int (&myArray)[100] parenthesis that enclose the &myArray are necessary. if you don't use them, you will be passing an array of references and that is because the subscript operator [] has higher precedence over the & operator.

E.g. int &myArray[100] // array of references

So, by using type construction () you tell the compiler that you want a reference to an array of 100 integers.

E.g int (&myArray)[100] // reference of an array of 100 ints

BugShotGG
  • 5,008
  • 8
  • 47
  • 63
cpx
  • 17,009
  • 20
  • 87
  • 142
  • 1
    "if you don't use them, you will be passing an `array of references`" - which of course, cannot exist, so you'd get a compile error. It's amusing to me that the operator precedence rules insist this must happen by default anyway. – underscore_d Aug 30 '16 at 15:27
  • Is there's any more tutorial about type construction () ? – iartist93 Dec 01 '16 at 19:32
  • 1
    Thanks, I needed an explanation that included the reason about operator precedence, which gives a sense to why it should be done this way. – cram2208 Nov 07 '17 at 05:43
  • @BugShotGG, thanks so much for providing me with a head-slap "oh, that's what's causing this" moment by mentioning operator precedence. I guess this is inevitable because [] needs left to right associativity while & needs right to left so they can't be in the same level. And I guess ++/-- need to be above & so pointer incrementation works as expected. Thanks again. – Erik Sep 22 '22 at 08:03
19

The following creates a generic function, taking an array of any size and of any type by reference:

template<typename T, std::size_t S>
void my_func(T (&arr)[S]) {
   // do stuff
}

play with the code.

User12547645
  • 6,955
  • 3
  • 38
  • 69
  • 2
    [Good writeup on how to use this pattern to make a safe strcpy](https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/). – idbrii Nov 16 '20 at 22:15
6

Arrays are default passed by pointers. You can try modifying an array inside a function call for better understanding.

  • 3
    Arrays can not be passed by value. If the function receives a pointer, an array decays to a pointer to its first element. I'm not sure what you are trying to say here. – Ulrich Eckhardt Jul 19 '15 at 08:50
  • @UlrichEckhardt I'm trying to say that "Arrays can not be passed by value" as you said before, they are default passed by reference – Eduardo A. Fernández Díaz Jul 24 '15 at 21:52
  • 8
    Array are neither passed by value nor reference. They are passed by pointers. If arrays are passed by reference by default, you will have no problem using sizeof on them. But that is not the case. Arrays decays to pointers when passed into a function. – user3437460 May 27 '16 at 16:43
  • 3
    Arrays can be passed by reference OR by degrading to a pointer. For example, using `char arr[1]; foo(char arr[]).`, arr degrades to a pointer; while using `char arr[1]; foo(char (&arr)[1])`, arr is passed as a reference. It's notable that the former form is often regarded as ill-formed since the dimension is lost. – zl9394 Feb 11 '17 at 00:14
  • 1
    Re, "Arrays are...passed by pointers." That description sounds unconventional at best, and it may be confusing to newbies. The _name_ of an array variable, is a valid expression whose value is a pointer the the first member of the array. If you have some function `foo(T* t)`, and you have an array `T a[N];` then when you write `foo(a);` I think it would be more correct to say that you are passing a pointer, not passing an array, and you are passing the pointer by value. – Solomon Slow Jun 15 '20 at 15:09
  • It's important to distinguish between a parameter declared as an array reference and a parameter declared as simply an array type. The latter will effectively be treated as a pointer via 'decay to pointer' semantics and the size of the array will be ignored. The former though will be able to enforce the correct array size through the type system and in a template context the size of the passed array can be deduced. – halfflat May 11 '22 at 09:39
  • 1
    @user3437460 Commenting on old comment since it has a lot of votes: **in C++ arrays can be passed by reference**. – hyde Oct 20 '22 at 11:15