Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: Passing Struct to a Function doesn't result in a call by value operation

I have the following problem with a program which I wrote in Visual C++ and I hope that anyone can help me please:

typedef struct spielfeld
{
 int ** Matrix;
 int height; 
 int width; 
 Walker walker;
 Verlauf history;
} Spielfeld;

void show(Spielfeld fieldToShow); //Prototype of the Function where I have this
                                  //problem

int main(int argc, char *argv[])
{
  int eingabe;
  Spielfeld field;

  //Initialize .. and so on

  //Call show-Function and pass the structure with Call by Value
  show(field);
  //But what's happened? field.Matrix has changed!!
  //can anyone tell me why? I don't want it to become changed!
  //cause that's the reason why I pass the field as Call by Value!
}

void show(Spielfeld fieldToShow)
{
 //Here is the problem: Alltough the parameter fieldToShow has been passed
 //with call by value, "fieldToShow.Matrix[0][0] = 1" changes the field in 
 //main!!
 fieldToShow.Matrix[0][0] = 1;

 //Another try: fieldToShow.walker.letter only affects the local fieldToShow, 
 //not that field in main! That's strange for me! Please help!
 fieldToShow.walker.letter  = 'v';
}
like image 477
David Avatar asked Nov 22 '25 04:11

David


2 Answers

When you pass the structure in, you are passing it in by value. However, the matrix within it is implemented as a pointer to pointer to int. Those pointers are references, and so when you modify the value referenced by them in your function, the same value is referenced by the original structure in main.

If you want to pass these objects by value, you need to do a deep copy yourself, in which you allocate a new matrix, and copy all of the values from the original matrix into it.

As Drew points out, in C++, the preferred way to implement that deep copy is via a copy constructor. A copy constructor allows you to perform your deep copy any time your object is passed by value, without having to explicitly copy the object yourself.

If you are not ready for classes and constructors yet, you can simply write a function, perhaps Spielfeld copySpielfeld(Spielfeld original), that will perform that deep copy; it will essentially be the same as your initialization code that you elided in your example, except it will take values from the Spielfeld passed in, instead of creating a new Spielfeld. You may call this before passing your field into the show function, or have the show function do it for any argument passed in, depending on how you want your API to work.

like image 62
Brian Campbell Avatar answered Nov 23 '25 18:11

Brian Campbell


You're copying the pointer when you pass fieldToShow. Pass-by-value does not perform a deep copy, so both the Spielfeld in an invocation of show(...) and main(...) (although distinct) have the same value for Matrix.

Fixing this is non-trivial. Probably the easiest thing to do would be to change show(...) to pass-by-reference (using a Spielfeld* basically) and make an explicit copy at the start of the function.

like image 26
Kevin Montrose Avatar answered Nov 23 '25 17:11

Kevin Montrose



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!