簡體   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