2010-01-08 70 views
2

我有我在Visual C++編寫了一個程序下面的問題,我希望有人能幫助我,請: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'; 
} 

回答

9

當您傳遞結構時,您將按值傳遞它。但是,其中的矩陣實現爲指向int的指針。這些指針是引用,所以當您修改函數中引用的值時,main中的原始結構會引用相同的值。

如果您想通過值傳遞這些對象,您需要自己做一個深層複製,在其中分配一個新矩陣,並將原始矩陣中的所有值複製到其中。

正如Drew指出的那樣,在C++中,實現該深度副本的首選方式是通過copy constructor。複製構造函數允許您在對象按值傳遞時執行深度複製,而無需自行顯式複製對象。

如果你還沒有準備好類和構造函數,你可以簡單地寫一個函數,可能是Spielfeld copySpielfeld(Spielfeld original),它將執行深度複製;它基本上與您在示例中省略的初始化代碼基本相同,只不過它會從傳入的Spielfeld中取值,而不是創建新的Spielfeld。您可以在將field傳遞給show函數之前調用此函數,或者讓show函數爲傳入的任何參數執行此操作,具體取決於您希望API的工作方式。

+1

理想情況下,如果你使用C++,這將拷貝構造函數中完成。 –

+0

是的,這確實是正確的,雖然他似乎在這裏編寫C代碼,所以我不知道他是否知道足夠的C++能夠應用該代碼。 –

1

該結構開始按值傳遞,但由於它包含一個指針(矩陣),該指針指向的內容可由任何有權訪問該結構的人更改。如果你不希望發生這種情況,你可以使指針爲常量。

3

當您通過fieldToShow時,您正在複製指針。按值傳遞不執行深度複製,因此調用show(...)main(...)(儘管不同)的Spielfeld對於Matrix都具有相同的

修復這是非平凡的。可能最簡單的做法是將show(...)更改爲通過引用(基本上使用Spielfeld*),並在函數的開頭進行明確的複製。

2

當你施皮爾費爾德對象被複制:

  • 副本都有自己的「行者」,這是原來的「步行者」的副本。由於walker是一個結構,這意味着你有兩個結構。
  • 該副本有其自己的「Matrix」成員,該成員是原始「Matrix」成員的副本。但矩陣是一個指針,這意味着你有兩個指針。指針的副本指向原始指向的相同內容。

因此,修改副本的步行者的內容不會影響原始,因爲他們有不同的步行者。對副本矩陣內容的修改確實會影響原始內容,因爲它們共享相同的矩陣。

0

作爲有趣的瑣事:這是如何通過價值調用在java中工作。對象引用總是按值傳遞。如果你操縱這些引用指向的難度很高的對象,就會發生引用調用的情況。

與你的問題確實沒有關係,但也許你會發現interestring。

快樂黑客