-->

Passing 2D array by value doesn't work

2019-09-22 13:37发布

问题:

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?.

回答1:

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];  
         }
     }
}


回答2:

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.



回答3:

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.



回答4:

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;
}