【问题标题】:C: Passing Struct to a Function doesn't result in a call by value operationC:将结构传递给函数不会导致按值操作调用
【发布时间】:2010-01-08 17:38:46
【问题描述】:

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

【问题讨论】:

    标签: c function struct parameter-passing


    【解决方案1】:

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

    如果你想通过值传递这些对象,你需要自己做一个深拷贝,你在其中分配一个新的矩阵,并将原始矩阵中的所有值复制到其中。

    正如 Drew 指出的那样,在 C++ 中,实现深拷贝的首选方式是通过 copy constructor。复制构造函数允许您在任何时候通过值传递对象时执行深层复制,而无需自己显式复制对象。

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

    【讨论】:

    • 理想情况下,如果您使用的是 C++,那将在复制构造函数中完成。
    • 是的,这确实是正确的,虽然他似乎在这里编写 C 代码,所以我不知道他是否知道足够的 C++ 能够应用它。
    【解决方案2】:

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

    解决此问题并非易事。可能最简单的做法是将 show(...) 更改为 pass-by-reference(基本上使用 Spielfeld*)并在函数开始时进行显式复制。

    【讨论】:

      【解决方案3】:

      当您的 Spielfeld 对象被复制时:

      • 副本有自己的“walker”,是原版“walker”的副本。由于 walker 是一个结构,这意味着您有两个结构。
      • 副本有自己的“Matrix”成员,它是原始“Matrix”成员的副本。但是 Matrix 是一个指针,这意味着你有两个指针。指针的副本指向原始指向的对象。

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

      【讨论】:

        【解决方案4】:

        该结构是按值传递的,但是由于它包含一个指针(矩阵),因此该指针所指向的内容可以被任何有权访问该结构的人更改。如果您不希望这种情况发生,您可以将指针设为 const。

        【讨论】:

          【解决方案5】:

          作为有趣的琐事:这就是 java 中按值调用的工作方式。对象 references 总是按值传递。如果你很难操作这些引用指向的对象,就会感觉发生了引用调用。

          与您的问题实际上无关,但也许您觉得这很有趣。

          黑客愉快

          【讨论】:

            猜你喜欢
            • 2018-03-30
            • 2015-10-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-06
            相关资源
            最近更新 更多