2011-12-13 43 views
0

我無法使用cin方法獲取變量。當輸入是一個數字時沒有問題,但是當它是一個特殊字符,如點[。],while循環到無窮大時。 我在做什麼錯?當cin的輸入是'點'時循環到無限

cout << "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
    cin >> *race; 
    while(*race<1||*race>3) 
    { 
    system("cls"); 
    cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
    cin >> *race; 
    } 

我搜索的答案,我應該有刷新緩衝區,但我不「噸得到如何做到這一點。我是相當新的C + +。感謝名單

+2

什麼是種族? –

+0

變數競賽是一個INT – Rps

+0

@RPS:不,它不是。如果'race'的類型是'int',那麼'* race'將是一個錯誤,編譯器會拒絕它。 –

回答

2

race的字符,然後你將能夠做到:

while (*race < '1' || *race > '3') 

這可能是你想達到什麼

說明:

當您將cin >>轉換爲int時,它將給定的ASCII字符串轉換爲整數值。 .沒有整數意義,所以它不會被讀入race,並且failbit已被設置 - 除非您清除它們,否則它們將爲空操作。但是,如果您將cin >>轉換爲char並將其與其他char s(以及它們的ASCII代碼,實際上)進行比較,您將可以毫無困難地檢查它。

+0

解決方案可能是實際需要的(儘管它沒有解決所有問題),但解釋是不正確的。當你把'cin >>'變成一個'int',並且輸入流包含一個''.''時,''失敗位'被設置在'cin'中,並且所有進一步的輸入在清除之前變爲空操作。 (當然,他也需要刪除違規字符;'cin.ignore(INT_MAX,'\ n');'可能是最合適的。)如果有的話,你的解決方案將進入無限循環'cin'上的任何其他錯誤,就像文件結尾一樣。 –

+0

嗯,看起來你通常是正確的,但在上一個陳述中是錯誤的 - 你不會從'stdin'獲得EOF。 – Griwes

+0

既然什麼時候?該標準肯定支持它,並且我知道了所有的實現。 'cin'遇到文件結尾時應該發生什麼,如果不是文件結束的情況? –

1

除了一個接受的其他解決辦法是清除CIN的failbit而忽略了最後一個輸入象下面這樣:

cout << "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
cin >> *race; 
while(*race<1||*race>3) 
{ 
    // Clears the state of cin to be in good state 
    cin.clear(); 
    // Ignores the last input read so that it's not read back again 
    cin.ignore(); 
    system("cls"); 
    cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
    cin >> *race; 
} 
+0

這不是你正在清除的'badbit',而是'failbit'。 (但'cin.clear()'將它們全部清除,並且是正確的解決方案。) –

+0

@JamesKanze:感謝您的更正。爲那些對此解決方案感興趣的人編輯答案。 –

1

這個例子正是再現您的問題:

#include <iostream> 

int main() 
{ 
    int i = 5; 
    while (i < 1 || i > 3) 
    { 
     std::cin >> i; 
    } 
} 

這裏發生了什麼:當operator>>未能讀取一個整數(例如,當您鍵入一個點並按回車鍵)時,您鍵入的任何內容都會在流中保留,包括換行符。 因此,在while循環的下一次迭代中,下一個輸入已經存在,因爲它不是有效整數,所以循環永遠不會中斷。 您需要確保在operator>>失敗時清空流並清除所有已設置的錯誤標誌。

#include <iostream> 
#include <limits> 

int main() 
{ 
    int i = 5; 
    while (i < 1 || i > 3) 
    { 
     if (!(std::cin >> i)) 
     { 
      // clear streams internal error flags 
      std::cin.clear(); 
      // ignore what's left in the stream, up to first newline character 
      // or the entire content, whichever comes first 
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
     } 
    } 
} 
1

你的代碼有幾個問題。首先是你不要 驗證你的輸入成功;對於 while正確的條件應該是:

while (!cin || (*race < 1 || *race > 3)) 

書面,如果輸入失敗(這是發生了什麼事,當你 輸入'.',假設race的類型爲int*),然後*race 包含其以前的價值,不管那是什麼。

第二個是如果你從cin得到一個錯誤,你不清楚 它。一旦流處於錯誤狀態,它將保持這種狀態,直到您明確清除它爲止。如果cin失敗,你需要執行:

cin.clear(); 

某處循環。

第三個是,如果cin失敗了,你不提取其 使它失敗,使清除錯誤狀態後,你需要 提取它的字符。鑑於你的結構化對話的方式,你可能 要不顧一切,直到行的末尾:

cin.ignore(INT_MAX, '\n'); 

您可能要做到這一點,即使cin沒有失敗,無論是在環 (如果由於*race < 1 || *race > 3條件而被輸入),或者在 成功的情況下。或者,你可能要轉移到閱讀的線條, 並確保該行只包含 你感興趣的字符後的空白。

這最後的解決方案是一個我會採用,因爲它處理了相當多 所有上述問題。所以,我的代碼看起來是這樣的:

// return -1 on error in input, 
// throw exception on (unexpected) end of file 
int 
getRace(std::istream& source) 
{ 
    std::string line; 
    if (!std::getline(source, line)) { 
     throw std::ios_base::failure("Unexpected end of file"); 
    } 
    std::istringstream tmp(line); 
    int results; 
    return tmp >> results >> std::ws && tmp.get() == EOF 
     ? results 
     : -1; 
} 

// ... 
int race = -1; 
while (race < 0) { 
    std::cout << "What is your race\n" 
       "1. Human\n" 
       "2. Troll\n" 
       "3. Zombie\n" << std::flush; 
    race = getRace(std::cout); 
    if (race < 0) { 
     std::cout << "Wrong choice" << std::endl; 
    } 
} 

注意,通過線路輸入,您避免出現任何問題與 重置格式錯誤,跳過錯誤輸入或 情況下錯誤的重新同步。