2014-02-22 144 views
1

我一直在研究這個程序好一兩個小時,現在每次我嘗試調試它時,visual studio正在決定更改currentGuess.guessLine中的值,我不知道爲什麼。他們沒有通過引用傳遞任何地方,他們應該改變的唯一時間是在「來自用戶的猜測」評論之下。有人能幫助,因爲它讓我瘋狂?我已經提供了下面的代碼:(我已經刪除了任何完全不相關的方法,使其更短)Visual Studio傳遞變量作爲參考?

我正在使用visual studio專業版,並且我已經重寫了3次此代碼,我仍然無法弄清楚它爲什麼是發生的事情。任何幫助,將不勝感激。

struct History 
    { 
     public Guess[] previousGuesses; 
     public int noOfPreviousGuesses; 
    } 
    struct Guess 
    { 
     public int[] guessLine; 
     public Hint givenHint; 
    } 
    struct Hint 
    { 
     public int blackPegs; 
     public int whitePegs; 
    } 

    static void Main(string[] args) 
    { 
     Mastermind(3, 3); 
    } 

    static void Mastermind(int N, int M) 
    { 
     bool gameFinished; 
     int playAgain; 
     History gameHistory; 
     Guess currentGuess; 
     int[] secretCode; 

     do 
     { 
      //Game start 
      gameFinished = false; 

      //Reset history 
      gameHistory.previousGuesses = new Guess[0]; 
      gameHistory.noOfPreviousGuesses = 0; 

      //Generate secretCode 
      secretCode = GenerateSecretCode(N, M); 

      do 
      { 
       //Get guess from user 
       currentGuess.guessLine = GetGuessLine(N, M); 

       //Evaluate guess 
       gameFinished = EvaluateGuess(currentGuess.guessLine, secretCode, N); 

       if (gameFinished == false) 
       { 
        //Generate hint 
        currentGuess.givenHint = GenerateHint(currentGuess.guessLine, secretCode, N); 

        //Add guess to history 
        gameHistory = AddGuessToHistoryQueue(currentGuess, gameHistory); 

        //Output history 
        OutputHistory(gameHistory, N); 
       } 

      } while (gameFinished == false); 

      //Ask to play again 
      playAgain = GetValueFromUser("Enter 0 or a positive value to play again, otherwise enter a negative value: "); 

     } while (playAgain >= 0); 
    } 

    /// <summary> 
    /// Gets a guess line from the user. 
    /// Validates each value using above procedure. 
    /// </summary> 
    /// <param name="codeLength">The length of the code being used.</param> 
    /// <param name="noOfColours">The number of colours allowed.</param> 
    /// <returns>The line entered.</returns> 
    static int[] GetGuessLine(int codeLength, int noOfColours) 
    { 
     int[] guessLine; 

     guessLine = new int[codeLength]; 

     for (int count = 0; count < codeLength; count++) 
     { 
      //Get guessLine[count] from user 
      guessLine[count] = GetValueFromUserInRange(1, noOfColours, "Please enter guess at position " + count + ": "); 
     } 

     return guessLine; 
    } 

    /// <summary> 
    /// Compares the given guess to the given code. 
    /// Returns true if guess and code match exactly otherwise 
    /// returns false. 
    /// </summary> 
    /// <param name="guess">The guess being compared.</param> 
    /// <param name="code">The code to be compared against.</param> 
    /// <param name="codeLength">The length of the code and guess.</param> 
    /// <returns></returns> 
    static bool EvaluateGuess(int[] guess, int[] code, int codeLength) 
    { 
     bool correctGuess; 

     correctGuess = true; 

     for (int count = 0; count < codeLength; count++) 
     { 
      if (guess[count] != code[count]) 
      { 
       //Found inconsistency 
       correctGuess = false; 
       break; 
      } 
     } 

     return correctGuess; 
    } 

    /// <summary> 
    /// Generates a hint through finding all matching values, 
    /// changing their values and incrementing the black pegs total. 
    /// Then calculates white pegs by checking for matching values again. 
    /// </summary> 
    /// <param name="guess">The guess requiring a hint.</param> 
    /// <param name="code">The code for the guess to be compared to.</param> 
    /// <param name="codeLength">The length of the code/guess.</param> 
    /// <returns>The hint generated.</returns> 
    static Hint GenerateHint(int[] guess, int[] code, int codeLength) 
    { 
     Hint newHint; 

     newHint.blackPegs = 0; 
     newHint.whitePegs = 0; 

     //Calculate blackPegs 
     for (int count = 0; count < codeLength; count++) 
     { 
      if (guess[count] == code[count]) 
      { 
       newHint.blackPegs = newHint.blackPegs + 1; 

       //Hide values 
       guess[count] = 0; 
       code[count] = 0; 
      } 
     } 

     //Calculate white pegs 
     for (int guessCount = 0; guessCount < codeLength; guessCount++) 
     { 
      //Ensure current guess value hasn't been used 
      if (guess[guessCount] != 0) 
      { 

       //Check for matching value in code 
       for (int codeCount = 0; codeCount < codeLength; codeCount++) 
       { 
        if (guess[guessCount] == code[codeCount]) 
        { 
         //Found match 
         newHint.whitePegs = newHint.whitePegs + 1; 

         //Hide values 
         guess[guessCount] = 0; 
         code[codeCount] = 0; 
        } 
       } 

      } 
     } 

     return newHint; 
    } 
+1

點'INT []'是引用類型,所以通過'INT []'由值只是傳遞對同一個數組的引用。它不會複製數組的元素。 – hvd

+0

我的猜測是,因爲你只有一個struct currentGuess引用,你修改了這個值,這可能會導致一個問題。你能解釋一下你正在經歷什麼,因爲你對症狀的解釋有點含糊。記住,即使結構是一個值類型,你仍然持有對你正在修改的主遊戲循環中的結構的引用 – Charleh

+0

如果我錯了,請原諒我,我的C#知識不是很好,但可以當你將猜測行傳遞給GenerateHint函數時,它正在傳遞我的引用,就像在C/C++中傳遞數組指針一樣?我注意到你正在設置該函數中的[count] = 0。 – Mrfence97

回答

4

這是一個常見的錯誤很多開發商做。參數可爲ByValByRef(用VB表示法)進行傳遞。但是,這樣做是不正是大多數人假設它的確如此

對於值類型(例如int等 - 任何駐留在堆棧中的東西)。該值本身被複制到一個新的內存空間中,並傳入該方法。因此,對該值的更改不會影響原始值。

對於引用類型(例如對象,類等 - 駐留在堆中的任何東西)。 指針被複制並傳入該方法。但是,指針仍然是指向內存中的同一個對象。因此,對象內部屬性的更改仍會反映在調用方法中。這不會反映的唯一的事情,就是如果你這樣做:

myObject = new Person(); 

在這一點上,傳遞到方法的指針會被重置爲指向一個全新的對象。但是來自調用方法的原始指針仍然是指向原始對象。因此它不會看到這些變化。

想到的最簡單的事情之一(如果這是真的,我不是100%確定的,但它可以更容易地考慮這一點)。是指針到堆中的對象並存儲在堆棧中。當您設置byvalbyref/ref時,此操作將作用於堆棧中的對象,而不是堆中的對象。即Byval/ByRef 只有適用於堆。

編輯 Here是Jon Skeet支持的答案。他還鏈接到this文章

更新

根據您的評論附加信息。你的結構包含引用類型(int[]是一個ints數組 - 數組是引用類型),所以它們自動移動到堆中(據我所知,至少)。

This answer剷球它從略微不同的角度(結構是一個類的一部分),但我認爲它得到跨

+1

嗨,謝謝,爲了您的快速響應。好吧,我明白你來自哪裏。有沒有辦法解決這個問題? – Sciprios

+0

您可以修改代碼,將傳入對象中的值讀入局部變量,然後對該局部變量執行操作。 –

+0

但是根據[Microsoft:](http://msdn.microsoft.com/en-us/library/8b0bdca4.aspx)雖然我的代碼運行方式不同,但不通過引用傳遞結構體? – Sciprios