繁体   English   中英

C:将结构传递给函数不会导致按值运算调用

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

我在Visual C ++中编写的程序存在以下问题,希望有人能帮助我:

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

当您传入结构时,您将按值传递它。 但是,其中的矩阵实现为指向int的指针。 这些指针是引用,因此当您在函数中修改它们引用的值时, main的原始结构将引用相同的值。

如果要按值传递这些对象,则需要自己进行深层复制,在其中分配新矩阵,并将原始矩阵中的所有值复制到其中。

正如Drew所指出的,在C ++中,实现深度复制的首选方法是通过复制构造函数 复制构造函数允许您在按值传递对象时执行深层复制,而无需自己显式复制对象。

如果你还没有为类和构造函数做好准备,你可以简单地编写一个函数,也就是Spielfeld copySpielfeld(Spielfeld original) ,它将执行那个深层复制; 它基本上与您在示例中省略的初始化代码相同,除了它将从传入的Spielfeld获取值,而不是创建新的Spielfeld 您可以在将field传递给show函数之前调用它,或者让show函数为传入的任何参数执行此操作,具体取决于您希望API如何工作。

您在传递fieldToShow时正在复制指针。 按值传递不执行深层复制,因此在调用show(...)main(...) (尽管不同)时Spielfeld具有相同的Matrix

解决这个问题并非易事。 可能最简单的方法是将show(...)更改为pass-by-reference(基本上使用Spielfeld* )并在函数的开头创建一个显式副本。

复制Spielfeld对象时:

  • 该副本有自己的“助行器”,这是原版“助行器”的副本。 由于walker是一个结构,这意味着你有两个结构。
  • 该副本具有自己的“Matrix”成员,该成员是原始“Matrix”成员的副本。 但Matrix是一个指针,这意味着你有两个指针。 指针的副本指向原始指向的相同内容。

因此,对副本助行器内容的修改不会影响原件,因为它们具有不同的助行器。 对副本矩阵内容的修改会影响原始内容,因为它们共享相同的矩阵。

结构以值开始传递,但由于它包含指针(矩阵),因此指针所指向的内容可由有权访问该结构的任何人更改。 如果您不希望发生这种情况,可以使指针成为常量。

作为有趣的琐事:这是按值调用java的方式。 对象引用始终按值传递。 如果你操纵这些引用所指向的对象很难,那么就会觉得通过引用调用了。

真的与你的问题无关,但也许你发现了这个问题。

快乐的黑客

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM