電腦遊戲製作開發設計論壇 首頁 電腦遊戲製作開發設計論壇
任何可以在PC上跑的遊戲都可以討論,主要以遊戲之製作開發為主軸,希望讓台灣的遊戲人有個討論、交流、教學、經驗傳承的園地
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入 

Google
[C++疑難雜症]cin無限迴圈錯誤

 
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式初級班:語法及基礎概念
上一篇主題 :: 下一篇主題  
發表人 內容
yag
Site Admin


註冊時間: 2007-05-02
文章: 688

2673.35 果凍幣

發表發表於: 2007-6-3, PM 4:37 星期日    文章主題: [C++疑難雜症]cin無限迴圈錯誤 引言回覆

詳細症狀請看[7]if、goto、隨機亂數、邏輯和關係運算子、算術運算子

大致就是將非數字字元用cin讀入某數字型態變數時,cin會發生錯誤,若這錯誤是發生於迴圈中,那麼就可能造成無限迴圈。

我在網路上找到一篇相關解說及處理方式的文章,不過是英文的,有興趣的可以看看看:
http://cs.nmhu.edu/personal/curtis/cs1htmlfiles/cs1ch11sec2.htm
這個網頁中比較後半段「E. Handling Invalid Input」的段落就是在說這種形態的錯誤及解決辦法。

會產生這種錯誤,是因為cin在遇到把非數字字元丟給數字型態變數時,會將狀態設成fail,然後鎖死輸入的機制,使得輸入這行直接跳過不處理,如果這個輸入又是迴圈的結束條件,那麼自然就會產生無限迴圈,而那個變數的值就會保持在最後一個正常值的狀況下。
解決的方法很簡單,只要在迴圈中加入下面的程式碼即可:
代碼:
if( cin.fail() )
{
   cin.clear();
   char ch1;
   cin >> ch1;
   cout << "錯誤型態的輸入!" << endl;
}
這段程式碼的意思就是,當cin發生錯誤時,將錯誤狀態清除,宣告一個字元型態變數,將出錯的那個字元讀出來(此字元沒有用處,只是為了清空cin的串流,還是得讀出來),然後輸出錯誤訊息。
如此一來,就可以解決掉無限迴圈的問題,下次再到cin的位置時,就會要求再度輸入訊息,而不會直接略過。

話說為何在[7]if、goto、隨機亂數、邏輯和關係運算子、算術運算子的範例中輸入浮點數就會造成無限迴圈,那是因為當cin後面是整數變數時,它只會將浮點數小數點前面的數字丟給整數變數,後面的,就會在下一次的cin時才丟出來。
也因此,假設我輸入2.2,那麼我就會是先出石頭,如果電腦出剪刀或布,那麼接下來的這個「.」剛好丟給yesno當成願意繼續,之後第二局又是出石頭,然後直接到達詢問是否繼續的地方,因為畫面太快,我之前試的時候還以為看起來滿正常的,後來才發現,上面輸贏記錄的地方已經更新過了,代表這是第二局了。
如果第一局就平手,那麼這個「.」就會直接丟給第二次的choice,直接就進入了無限迴圈。大致就是這樣,有興趣的可以多試試,可以對程式流程有多一點體認。

以下附上更新後的猜拳遊戲程式碼:
代碼:
#include <iostream>
#include <time.h>

using namespace std;

int main()
{
   char yesno;
   short choise = 0, computer = 0;
   int win = 0, lose = 0, deuce = 0;

   cout << "這是猜拳遊戲,請從剪刀、石頭、布中選擇其一," << endl
       << "規則是剪刀贏布,布贏石頭,石頭贏剪刀。" << endl;

   system( "pause" );
   system( "cls" );
   srand( (unsigned)time( NULL ) );

Choose:
   cout << "勝場:" << win << " 敗場:" << lose << " 平手:" << deuce << endl;
   cout << "請輸入1~3:(1.剪刀 2.石頭 3.布)" << endl;
   cin >> choise;

   if( cin.fail() )   // 只有多加了從這裡開始
   {
      cin.clear();
      char ch1;
      cin >> ch1;
      cout << "錯誤的輸入格式!" << endl;
      goto Choose;
   }                  // 到這裡結束的程式碼,其他地方都沒有異動

   if( choise < 1 || choise > 3 )
      goto Choose;

   computer = rand() % 3 + 1;

   if( choise == computer )
   {
      cout << "平手!" << endl;
      deuce++;
      goto Choose;
   }
   else if( (choise == 1 && computer == 3) || (choise == 2 && computer == 1) || (choise == 3 && computer == 2) )
   {
      cout << "你贏了!" << endl;
      win++;
   }
   else
   {
      cout << "你輸了!" << endl;
      lose++;
   }

   cout << "要繼續嗎?( y/n )" << endl;
   cin >> yesno;

   if( yesno != 'n' && yesno != 'N' )
   {
      system( "cls" );
      goto Choose;
   }
   
   return 0;
}

PS.感謝kage01的細心測試程式,找出此bug。
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
chongren
偶而上來逛逛的過客


註冊時間: 2009-07-27
文章: 14
來自: 台北
152.02 果凍幣

發表發表於: 2009-9-16, AM 11:29 星期三    文章主題: 引言回覆

請問一下程式中的cls是什麼意思啊?!
_________________
爬文?
爬文這種舉動不適合我這種腦殘
回頂端
檢視會員個人資料 發送私人訊息 參觀發表人的個人網站 雅虎訊息通 MSN Messenger
yag
Site Admin


註冊時間: 2007-05-02
文章: 688

2673.35 果凍幣

發表發表於: 2009-9-22, PM 12:26 星期二    文章主題: 引言回覆

chongren 寫到:
請問一下程式中的cls是什麼意思啊?!

請參考:[C++][7]if、goto、隨機亂數、邏輯和關係運算子、算術運算子
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
從之前的文章開始顯示:   
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式初級班:語法及基礎概念 所有的時間均為 台灣時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
可以 在這個版面附加檔案
可以 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作