Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't arrays be passed as function arguments?

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.

like image 838
Hudson Worden Avatar asked Aug 16 '11 03:08

Hudson Worden


People also ask

Can you pass arrays as function arguments?

A whole array cannot be passed as an argument to a function in C++. You can, however, pass a pointer to an array without an index by specifying the array's name.

Can arrays be passed to the functions by value?

Answer: An array can be passed to a function by value by declaring in the called function the array name with square brackets ( [ and ] ) attached to the end. When calling the function, simply pass the address of the array (that is, the array's name) to the called function.

What happens when we pass array as a function argument?

Call By Value & Call By Reference In C/C++ whenever we pass an array as a function argument, then it is always treated as a pointer by a function.

Can we pass array to function in C?

Returning an array is similar to passing the array into the function. The name of the array is returned from the function. To make a function returning an array, the following syntax is used. To store the array returned from the function, we can define a pointer which points to that array.


2 Answers

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 ints"; 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!)


Array names decay to pointers for pass-by-value

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]!

(Live demo.)


But you can work-around it!

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.


Or, better, a generic pass-by-reference approach

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.


The future...

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.

like image 113
Lightness Races in Orbit Avatar answered Sep 29 '22 10:09

Lightness Races in Orbit


So I see answers explaining, "Why doesn't the compiler allow me to do this?" Rather than "What caused the standard to specify this behavior?" The answer lies in the history of C. This is taken from "The Development of the C Language" (source) by Dennis Ritchie.

In the proto-C languages, memory was divided into "cells" each containing a word. These could be dereferenced using the eventual unary * operator -- yes, these were essentially typeless languages like some of today's toy languages like Brainf_ck. Syntactic sugar allowed one to pretend a pointer was an array:

a[5]; // equivalent to *(a + 5) 

Then, automatic allocation was added:

auto a[10]; // allocate 10 cells, assign pointer to a             // note that we are still typeless a += 1;     // remember that a is a pointer 

At some point, the auto storage specifier behavior became default -- you may also be wondering what the point of the auto keyword was anyway, this is it. Pointers and arrays were left to behave in somewhat quirky ways as a result of these incremental changes. Perhaps the types would behave more alike if the language were designed from a bird's-eye view. As it stands, this is just one more C / C++ gotcha.

like image 26
Dietrich Epp Avatar answered Sep 29 '22 12:09

Dietrich Epp