I am trying to pass a 2d array to a function. I don't want the actual array to be modified. So pass it by value. But my actual 2darray is getting modified.(when i modify myArray, x is getting modified). Why is it so?
int main(int argc, const char* argv[])
{
int x[3][3];
x[0][0]=2;
x[0][1]=2;
x[0][2]=2;
x[1][0]=2;
x[1][1]=2;
x[1][2]=2;
x[2][0]=2;
x[2][1]=2;
x[2][2]=2;
func1(x);
}
void func1(int myArray[][3])
{
int i, j;
int ROWS=3;
int COLS=3;
for (i=0; i<ROWS; i++)
{
for (j=0; j<COLS; j++)
{
myArray[i][j] =3;
}
}
}
And is it possible to pass a 2D array by value if we don't know both dimensions?.
to prevent func1 from being changed, change it to a const pointer.
void func1(const int (*myArray)[3])
{
int i, j;
int ROWS=3;
int COLS=3;
for (i=0; i<ROWS; i++)
{
for (j=0; j<COLS; j++)
{
// myArray[i][j] =3; //compilation error, is now const
cout <<" "<<myArray[i][j];
}
}
}
You can take advantage of the fact that arrays in user defined types are copied and assigned when instances of that type are copied or assigned, for example
template <size_t N, size_t M>
struct Foo
{
int data[N][M];
};
template <size_t N, size_t M>
void func1(Foo<N, M> foo)
{
foo.data[1][2] = 42;
}
int main()
{
Foo<3, 3> f;
f.data[0][0]=2;
...
func1(f);
}
Here, func1
has a local copy of the foo
, which has its own copy of the array. I have used templates to generalize to arbitrary sizes.
Note that C++ provides the std::array
template, which you could use instead of Foo
, so in real code you would do something like this:
#include <array>
template <typename T, size_t N, size_t M>
void func1(std::array<std::array<T, N>, M> arr)
{
arr[1][2] = 42;
}
int main()
{
std::array<std::array<int, 3>, 3> a;
a[0][0]=2;
...
func1(a);
}
If you are stuck with pre-C++11 implementations, you can use either std::tr1::array
(header <tr1/array>
or boost::array
from the boost library. It is also a nice exercise to roll out your own.
An array is passed as a pointer, and it is not very C++`ish to pass 2d arrays as pointer.
You should a class to encapsulate the array and pass a reference to that class.
This way the "user" doesn't know of the underlying implementation of your array as well and you can change it without affecting functionality later on.
And of course passing a const reference to a class instance will be as lightweight as passing pointers, hence there will be no performance impact.
In standard C++, section 8.3.5 Functions point 5 explains that:
After determining the type of each parameter, any parameter of type
“array of T” or “function returning T” is adjusted to be “pointer to
T” or “pointer to function returning T,” respectively.
This is why your function works in fact with a pointer and modifies the original value.
Point 8 explains further that:
If the type of a parameter includes a type of the form “array of
runtime bound of T”, “pointer to array of unknown bound of T”, or
“reference to array of unknown bound of T”, the program is ill-formed.
So, you have to know the size in advance.
Alternative:
If you'd like to work by value, better use standard containers, such as vectors (here, vector<vector<int>>
). Your x would then be declared in main() with:
vector<vector<int>> x(3, vector<int>(3)); // initialised vector of 3 vector of 3 ints
or even better, to get rid of your long list of assignments to the same constant:
vector<vector<int>> x(3, vector<int>(3, 2)); // vector of 3 vector of 3 ints with value 2
And your function be defined as:
void func1(vector<vector<int>> myArray)
{ // resets all existing values to 3.
for (size_t i = 0; i<myArray.size(); i++)
for (size_t j = 0; j<myArray[i].size(); j++)
myArray[i][j] = 3;
}