Apparently, we can pass complex class instances to functions, but why can't we pass arrays to functions?
-
3FWIW, this originated in C and as arrays (the primitive ones, not `std::vector` or `std::array`) carried over into C++ pretty much unchanged, I suspect that the reason is the same. – Sep 17 '11 at 13:11
-
@delnan, the reason is the same? what it is the "same" reason? Please be more specific. – Alcott Sep 17 '11 at 13:31
-
I believe that you can do it with boost::array (or tr1::array). – Brent Bradburn Sep 17 '11 at 19:43
-
1...(or std::vector), etc. Your question is about a design decision that someone made for C about 40 years ago. The answer to your question (for C++) is "who cares". This is a non-issue for modern C++ because it is generally a good idea to avoid declaring raw arrays (and raw pointers) whenever possible. It is preferable to use a higher level array class such as one of those that I listed. – Brent Bradburn Sep 17 '11 at 20:43
-
Because (1) Dennis Ritchie built a pointer/array equivalence deep into the C language 40+ years ago, and (2) it would be a really bad idea. – user207421 Mar 26 '15 at 07:27
9 Answers
The origin is historical. The problem is that the rule "arrays decay into pointers, when passed to a function" is simple.
Copying arrays would be kind of complicated and not very clear, since the behavior would change for different parameters and different function declarations.
Note that you can still do an indirect pass by value:
struct A { int arr[2]; };
void func(struct A);

- 35,456
- 20
- 106
- 151
-
3In C++, you can pass arrays to functions per reference. With function templates and non-type template arguments, you can even pass arbitrarily long arrays. – sbi Sep 17 '11 at 13:30
-
7The rule that arrays expression decay into pointers is not specific to function calls. In C, the decay happens in any context other than (a) the operand of the unary `&` address-of operator; (b) the operand of the unary `sizeof` operator; or (c) a string literal in an initializer used to initialize a character array (`char s[] = "hello";`); I think there are one or two other exceptions in C++, probably involving references. For example, in `int arr[10]; int *p; p = arr;` the decay occurs, but there's not a function call in sight. – Keith Thompson Sep 17 '11 at 21:02
-
1This somehow does not explain the current state of things at all. There is no problem in making arrays copyable and getting rid of weird implicit decaying to pointer. However that would probably require introduction of special syntax to convert array to pointer (like `@arr`) expressing intent to get a pointer to all items rather than pointer to first item (`&(arr[0])`), but all the operator symbols were already in use. Or just their code base of that time didn't require array copying so they decided to cut corners which turned out to be a bad decision on long run. – user7860670 Oct 25 '18 at 08:02
Here's another perspective: There isn't a single type "array" in C. Rather, T[N]
is a a different type for every N
. So T[1]
, T[2]
, etc., are all different types.
In C there's no function overloading, and so the only sensible thing you could have allowed would be a function that takes (or returns) a single type of array:
void foo(int a[3]); // hypothetical
Presumably, that was just considered far less useful than the actual decision to make all arrays decay into a pointer to the first element and require the user to communicate the size by other means. After all, the above could be rewritten as:
void foo(int * a)
{
static const unsigned int N = 3;
/* ... */
}
So there's no loss of expressive power, but a huge gain in generality.
Note that this isn't any different in C++, but template-driven code generation allows you to write a templated function foo(T (&a)[N])
, where N
is deduced for you -- but this just means that you can create a whole family of distinct, different functions, one for each value of N
.
As an extreme case, imagine that you would need two functions print6(const char[6])
and print12(const char[12])
to say print6("Hello")
and print12("Hello World")
if you didn't want to decay arrays to pointers, or otherwise you'd have to add an explicit conversion, print_p((const char*)"Hello World")
.

- 464,522
- 92
- 875
- 1,084
-
It's worth noting that some other languages *do* permit arrays to be passed as parameters. In Ada, for example, the equivalent of `int[5]` and `int[10]` *are* (or at least can be) the same type; they're just different subtypes. You can define an Ada routine that takes an integer array with any arbitrary bounds as a parameter, or (for a function) that returns such an array. The price paid for this is that the compiler has to generate code to do all the necessary bookkeeping and memory management. Such implicit code is generally not considered to be "in the spirit of C" (or of C++). – Keith Thompson Sep 17 '11 at 21:07
Answering a very old question, as Question is market with C++ just adding for completion purposes, we can use std::array and pass arrays to functions by value or by reference which gives protection against accessing out of bound indexes:
below is sample:
#include <iostream>
#include <array>
//pass array by reference
template<size_t N>
void fill_array(std::array<int, N>& arr){
for(int idx = 0; idx < arr.size(); ++idx)
arr[idx] = idx*idx;
}
//pass array by value
template<size_t N>
void print_array(std::array<int, N> arr){
for(int idx = 0; idx < arr.size(); ++idx)
std::cout << arr[idx] << std::endl;
}
int main()
{
std::array<int, 5> arr;
fill_array(arr);
print_array(arr);
//use different size
std::array<int, 10> arr2;
fill_array(arr2);
print_array(arr2);
}
The reason you can't pass an array by value is because there is no specific way to track an array's size such that the function invocation logic would know how much memory to allocate and what to copy. You can pass a class instance because classes have constructors. Arrays do not.

- 179,497
- 17
- 214
- 278
-
2If the array is declared as a[4], then you simply know the size at compile time. – quant_dev Sep 17 '11 at 14:36
-
1Yes, **if**. But the size isn't passed along with the array, they're not 'glued' together in the way that would be needed to permit arrays to be passed by value. – David Schwartz Sep 17 '11 at 14:42
-
@quant: in the original scope that is known, but where does the 4 go in the called function? – Dennis Zickefoose Sep 17 '11 at 14:46
-
what if we specifically declare array with size. For example, func(int array[20]). Still cant get the size in func? @DennisZickefoose – Sazzad Hissain Khan Oct 18 '16 at 13:10
-
1@SazzadHissainKhan Maybe in some language other than C++ where arrays work very differently from the way they work in C++. But in C++, you can pass a `char*` that you got from `malloc` to a function that expects an `int[4]`. And `sizeof` [doesn't do what you expect](http://ideone.com/PgZZ6o). – David Schwartz Oct 18 '16 at 17:28
Summery:
- Passing the Address of the array's first element
&a = a = &(a[0])
- New Pointer (new pointer, new address, 4 bytes, in the memory)
- Points to the same memory location, in different type.
Example 1:
void by_value(bool* arr) // pointer_value passed by value
{
arr[1] = true;
arr = NULL; // temporary pointer that points to original array
}
int main()
{
bool a[3] = {};
cout << a[1] << endl; // 0
by_value(a);
cout << a[1] << endl; // 1 !!!
}
Addresses:
[main]
a = 0046FB18 // **Original**
&a = 0046FB18 // **Original**
[func]
arr = 0046FB18 // **Original**
&arr = 0046FA44 // TempPTR
[func]
arr = NULL
&arr = 0046FA44 // TempPTR
Example 2:
void by_value(bool* arr)
{
cout << &arr << arr; // &arr != arr
}
int main()
{
bool a[3] = {};
cout << &a << a; // &a == a == &a[0]
by_value(arr);
}
Addresses
Prints:
[main] 0046FB18 = 0046FB18
[func] 0046FA44 != 0046FB18
Please Note:
- &(required-lvalue): lvalue -to-> rvalue
- Array Decay: new pointer (temporary) points to (by value) array address
readmore:
It was done that way in order to preserve syntactical and semantic compatibility with B language, in which arrays were implemented as physical pointers.
A direct answer to this question is given in Dennis Ritchie's "The Development of the C Language", see the "Critique" section. It says
For example, the empty square brackets in the function declaration
int f(a) int a[]; { ... }
are a living fossil, a remnant of NB's way of declaring a pointer;
a
is, in this special case only, interpreted in C as a pointer. The notation survived in part for the sake of compatibility, in part under the rationalization that it would allow programmers to communicate to their readers an intent to passf
a pointer generated from an array, rather than a reference to a single integer. Unfortunately, it serves as much to confuse the learner as to alert the reader.
This should be taken in the context of the previous part of the article, especially "Embryonic C", which explains how introduction of struct
types in C resulted in rejection of B- and BCPL-style approach to implementing arrays (i.e. as ordinary pointers). C switched to non-pointer array implementation, keeping that legacy B-style semantics in function parameter lists only.
So, the current variant of array parameter behavior is a result of a compromise: one the one hand, we had to have copyable arrays in struct
s, on the other hand, we wanted to preserve semantic compatibility with functions written in B, where arrays are always passed "by pointer".

- 312,472
- 42
- 525
- 765
The equivalent of that would be to first make a copy of the array and then pass it to the function (which can be highly inefficient for large arrays).
Other than that I would say it's for historical reasons, i.e. one could not pass arrays by value in C.
My guess is that the reasoning behind NOT introducing passing arrays by value in C++ was that objects were thought to be moderately sized compared to arrays.
As pointed out by delnan, when using std::vector
you can actually pass array-like objects to functions by value.

- 18,333
- 6
- 54
- 63
You are passing by value: the value of the pointer to the array. Remember that using square bracket notation in C is simply shorthand for de-referencing a pointer. ptr[2] means *(ptr+2).
Dropping the brackets gets you a pointer to the array, which can be passed by value to a function:
int x[2] = {1, 2};
int result;
result = DoSomething(x);
See the list of types in the ANSI C spec. Arrays are not primitive types, but constructed from a combination of pointers and operators. (It won't let me put another link, but the construction is described under "Array type derivation".)

- 9
- 1
-
You're not passing the address of the array, you're passing the address of the array's first element (same memory location, different type). The array indexing operation is by definition a combination of pointer arithmetic and the unary `*` dereferencing operator, but an array itself is just an array. What makes arrays less than first-class types in C is not the array objects themselves, but the limited set of operations on them. – Keith Thompson Sep 17 '11 at 20:59
-
You're talking about arrays as a programming concept: data structures from the programmer's point of view. I thought the question was why C syntax for array data seems to differ from other data. If you look at it as a question of language structure, it's because arrays are not primitives. They are pointer operations which behave almost like primitives. – KonradG Sep 18 '11 at 03:30
-
Most *operations* on arrays are implemented as pointer operations. Arrays *are not* pointers. For example, an array object is an array object, and defining an array object does not explicitly or implicitly create any pointer object. (And I'm not at all sure I understand what distinction you're making between "data structures" and "language structure".) – Keith Thompson Sep 18 '11 at 03:32
-
I'm not saying that arrays are pointers. But the "array type" in C is just the array operator dressed up to act like a data type. The result is quite a convincing imitation, but it it's not perfect. :) One quirk, as you mentioned, is that the array itself has no address. – KonradG Sep 19 '11 at 22:46
-
@KeithThompson As to the distinction, it's the difference between asking between what goes on "under the hood" vs asking "why was it made like that". – KonradG Sep 19 '11 at 22:58
-
What? Certainly array objects have addresses. `int arr[10]; int (*p)[10] = &arr;`. As for the "array type" being "just the array operator", I'm afraid that the sense of that statement eludes me. Types are not operators. An array type is an array type. You can declare and define objects of array types (i.e., array objects); such objects really are arrays, not anything else. The only way in which arrays fail to be first-class is that certain operations on arrays (such as assignment and parameter passing) are not provided; instead, arrays are usually manipulated via pointers. – Keith Thompson Sep 20 '11 at 00:43
actually, a pointer to the array is passed by value, using that pointer inside the called function will give you the feeling that the array is passed by reference which is wrong. try changing the value in the array pointer to point to another array in your function and you will find that the original array was not affected which means that the array is not passed by reference.

- 19
- 4