This is one of the bad features that C++ has inherited from C: Raw arrays cannot be passed as a copy to a function, although there is syntax that looks like it does.
void f(int v[]);
void f(int v[2]); // number is ignored here
are in C and C++ just another notation for
void f(int* v);
This is one of the reasons why std::array
was introduced. This can be used like a raw array, but provides the normal rules when used as a function argument.
#include <iostream>
#include <array>
// copy argument is not possible with raw array
void call_by_value(std::array<int, 2> array) {
array[0] = 5;
std::cout << "call_by_value: " << array[0] << ", " << array[1] << '\n';
}
// return is not possible with raw array
std::array<int, 2> return_array() {
return {8, 7};
}
int main() {
std::array<int, 2> array = {1, 2};
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
call_by_value(array);
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
array = return_array(); // assign array is not possible with raw arrays
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
}
main array: 1, 2
call_by_value: 5, 2
main array: 1, 2
main array: 8, 7
To make the confusion complete, it is very possible to pass pointers or references to raw arrays as function arguments. However, the syntax is not very nice and especially the pointer variant can easily be used incorrectly.
#include <iostream>
void call_by_reference(int(&array)[2]) {
array[0] = 5;
std::cout << "call_by_reference: " << array[0] << ", " << array[1] << '\n';
}
void call_by_pointer(int(*array)[2]) {
(*array)[1] = 7;
std::cout << "call_by_pointer: " << (*array)[0] << ", " << (*array)[1] << '\n';
}
int main() {
int array[2] = {1, 2};
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
call_by_reference(array);
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
call_by_pointer(&array);
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
}
main array: 1, 2
call_by_reference: 5, 2
main array: 5, 2
call_by_pointer: 5, 7
main array: 5, 7
In call_by_pointer
the brackets in (*array)[1]
are especially important for access!
#include <iostream>
#include <array>
void call_by_pointer(int(*array)[2]) {
std::cout << "call_by_pointer: " << *array[0] << ", " << *array[1] << '\n';
}
int main() {
int array[2] = {1, 2};
call_by_pointer(&array);
}
call_by_pointer: 1, -18532096
This program compiles without problems! But the element access is wrong. The access operator [x]
has priority over the dereference operator *
. Therefore, according to the pointer arithmetic for accessing element one in memory, the address is advanced by the size of an int
array with two elements and this is then dereferenced. But this is already outside the array, so memory garbage is output.
Again, std::array
improves the situation.
#include <iostream>
#include <array>
void call_by_reference(std::array<int, 2>& array) {
array[0] = 5;
std::cout << "call_by_reference: " << array[0] << ", " << array[1] << '\n';
}
void call_by_pointer(std::array<int, 2>* array) {
(*array)[1] = 7;
std::cout << "call_by_pointer: " << (*array)[0] << ", " << (*array)[1] << '\n';
}
int main() {
std::array<int, 2> array = {1, 2};
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
call_by_reference(array);
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
call_by_pointer(&array);
std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
}
main array: 1, 2
call_by_reference: 5, 2
main array: 5, 2
call_by_pointer: 5, 7
main array: 5, 7
The parameter syntax is easy to read and forgetting the parentheses in the pointer variant will result in a compilation error.