Why can't you pass arrays as function arguments?
I have been reading this C++ book that says 'you can't pass arrays as function arguments', but it never explains why. Also, when I looked it up online I found comments like 'why would you do that anyway?' It's not that I would do it, I just want to know why you can't.
Why can't arrays be passed as function arguments?
They can:
void foo(const int (&myArray)[5]) {
// `myArray` is the original array of five integers
}
In technical terms, the type of the argument to foo
is "reference to array of 5 const
int
s"; with references, we can pass the actual object around (disclaimer: terminology varies by abstraction level).
What you can't do is pass by value, because for historical reasons we shall not copy arrays. Instead, attempting to pass an array by value into a function (or, to pass a copy of an array) leads its name to decay into a pointer. (some resources get this wrong!)
This means:
void foo(int* ptr);
int ar[10]; // an array
foo(ar); // automatically passing ptr to first element of ar (i.e. &ar[0])
There's also the hugely misleading "syntactic sugar" that looks like you can pass an array of arbitrary length by value:
void foo(int ptr[]);
int ar[10]; // an array
foo(ar);
But, actually, you're still just passing a pointer (to the first element of ar
). foo
is the same as it was above!
Whilst we're at it, the following function also doesn't really have the signature that it seems to. Look what happens when we try to call this function without defining it:
void foo(int ar[5]);
int main() {
int ar[5];
foo(ar);
}
// error: undefined reference to `func(int*)'
So foo
takes int*
in fact, not int[5]
!
You can hack around this by wrapping the array in a struct
or class
, because the default copy operator will copy the array:
struct Array_by_val
{
int my_array[10];
};
void func (Array_by_val x) {}
int main() {
Array_by_val x;
func(x);
}
This is somewhat confusing behaviour.
In C++, with some template magic, we can make a function both re-usable and able to receive an array:
template <typename T, size_t N>
void foo(const T (&myArray)[N]) {
// `myArray` is the original array of N Ts
}
But we still can't pass one by value. Something to remember.
And since C++11 is just over the horizon, and C++0x support is coming along nicely in the mainstream toolchains, you can use the lovely std::array
inherited from Boost! I'll leave researching that as an exercise to the reader.