Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Passing an Array to a Function

Last updated Jan 1, 2003.

If youโ€™re looking for more up-to-date information on this topic, please visit our C/C++ Programming article, podcast, and store pages.

In a previous column, I claimed that passing an array as a function argument was impossible. The problem is that the array is implicitly converted, or decays, into a pointer. The pointer, alas, doesn't store the array's dimension; it doesn't even tell you that the variable in question is an array. I recently received an e-mail message from a reader who proposed a technique for passing arrays as arguments without the implicit conversion to pointers. Here it is:

"I'm not sure you are correct when you say in your article that functions in C++ can't receive array arguments. I have written functions that take array arguments before. It only works for statically sized arrays, and the parameter has to specify the size of the array, but it is possible. The syntax is something like:

void foo(int (&array)[10]);

which declares a function that takes an array of 10 integers. This does not seem useful at first, but by using template parameter deduction you can write generic functions that operate on statically sized arrays in this way:

template <typename T, size_t size>

void foo(T (&array)[size])
{
 //sort array, find the sum, min, max, etc
}

Of course as you say in your article, you have to be careful that the array does not decay to a pointer as you are passing it around. In this case though, the code should simply not compile since the template will not match."

Before I go on, let's parse the following function declaration, which might look a bit cryptic:

void foo(int (&array)[10]);

What's interesting here is how the parameter is declared: int (&array)[10] is a reference to an array of 10 ints. So, what gets passed on the callee's stack is actually a reference, not a real array; though, for most practical purposes, there is no difference between the two. (For a review of the three argument passing mechanisms of C++, see this section.)

Unlike passing an array by value, which causes the array to decay into a bare pointer, the use of a reference to a statically-allocated array is seemingly safer, because the callee has access to the type information associated with the array. Particularly, a sizeof() expression returns the correct array size even when used inside the callee:

void foo(int (&arr)[10])
{
 cout<<sizeof(arr)<<endl; //output: 40
}
int main()
{
 int arr[10];
 foo(arr);
}

When you use a reference to a statically sized array, the compiler is also capable of detecting type mismatches at the place of all:

int arr[5]; //wrong dimension
foo(arr); //compiler diagnostic

There are a few caveats here, though. The main problem is that a reference to an array is a slippery type -- you can inadvertently convert it to a bare pointer, thus losing important type information. Consider the following example:

void func(int* p) {}
void foo(int (&arr)[10])
{
 func(arr);
}

When func() is called, the argument arr decays into a pointer. Remember: once an array has decayed into a pointer, the array's type information is lost. This isn't the only problem that might arise, though. Consider the following typeid() expression. I expected it to produce a complete description of the array's type, including its dimension:

void foo(int (&arry)[10])
{
 cout<<typeid(arry).name()<<endl;
}

However, the cout expression reports "int *". We can conclude that there are limits as to how far you can push this technique. If it isn't used in generic functions that operate on statically sized arrays, I still recommend the array_wrapper class template presented in the original column as it offers a safer and efficient alternative.