[英]c++ validate number and stop infinity loop
我正在做一個控制台應用程序,我正在向應用程序傳遞一個整數,它工作正常,但如果我通過一封信,它會發瘋,
int opt=0;
std::cout<<"Pick lang:"<<'\n';
std::cout<<"1.[es-ES]:"<<'\n';
std::cout<<"2.[en-US]:"<<'\n';
std::cin >> opt;
while(opt<1 || opt>2)
{
std::cout<<"\nERROR!"<<'\n';
std::cout<<"Pick lang again:"<<'\n';
std::cout<<"1.[es-ES]:"<<'\n';
std::cout<<"2.[en-US]:"<<'\n';
std::cin >> opt;
}
我嘗試使用isdigit()但我得到了相同的結果。 謝謝
執行cin >>提取后,您要檢查cin流是否仍然良好。 如果你希望cin提取一個數字,但它會得到其他東西,例如。 就像一封信,然后流將被設置為一個糟糕的狀態,這就是為什么你看到它“變得瘋狂”。
你需要做的是輸入后,檢查cin是否仍然良好。 如果它處於錯誤狀態,則需要清除其標志,然后刪除流中的任何垃圾數據。 如果不這樣做,那么cin的后續使用將無法正常運行。
以您的代碼片段為例,您可以將其更改為以下內容:
int opt = 0;
bool inputGood = false;
do
{
std::cout << "Pick lang again:" << '\n';
std::cout << "1.[es-ES]:" << '\n';
std::cout << "2.[en-US]:" << '\n';
inputGood = std::cin >> opt;
if(!inputGood)
{
std::cout << "\nERROR! Invalid choice." << '\n';
cin.clear();
while( cin.get() != '\n' );
}
}while(!inputGood || opt < 1 || opt > 2);
編輯:在cin錯誤處理中whoops次要錯誤。 已更正,現在應該正常工作。 :)
問題是調用std::cin >> opt
無法解析字符並立即返回(不使用緩沖區),然后它找到相同的內容並失敗....
您應該檢查操作的結果並對其作出反應。 一種可能性是檢查失敗位( std::cin.fail()
)並使整個操作失敗或消耗部分緩沖區(可能是單個字符,可能更多,具體取決於您希望應用程序的行為方式)。
最簡單的事情可能不是讀取數字,而是讀取字符,然后與預期字符進行比較:
char opt = 0;
do {
// prompt user for input
if (! (std::cin >> opt) ) {
// io error, report and bail out
break;
}
} while ( opt != '0' && opt != '1' );
插入字母時會發生這種情況:
operator>>
從流中提取字符並嘗試將它們轉換為數字; ios::failbit
並返回; opt
可能不受影響(標准將這些東西委托給語言環境庫,這是我從未真正理解的C ++區域 - 對於勇敢的,它是在§22.2.2.1.2); opt
保持原樣,循環繼續; std::cin >> opt;
, operator>>
看到狀態仍然是ios::failbit
,所以它甚至都沒有嘗試提取任何東西; 要解決此問題,您應該清除錯誤狀態並從輸入緩沖區中刪除“錯誤”字符。 既然你可能不想將所有代碼添加到每個cin>>
,那么創建一個處理這個常見問題的函數是很有用的。 就個人而言,我創建了這個已被證明有用多次的AcquireInput.hpp
( AcquireInput.hpp
):
#ifndef ACQUIREINPUT_HPP_INCLUDED
#define ACQUIREINPUT_HPP_INCLUDED
#include <iosfwd>
#include <limits>
#include <string>
template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
do
{
Os<<Prompt.c_str();
if(Is.fail())
{
Is.clear();
Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Is>>Result;
if(Is.fail())
Os<<FailString.c_str();
} while(Is.fail());
}
template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
InType temp;
AcquireInput(Os,Is,Prompt,FailString,temp);
return temp;
}
/* Usage example:
//1st overload
int AnInteger;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);
//2nd overload (more convenient, in this case)
int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
*/
#endif
直接讀數是有問題的
如果std :: cin顯示輸入它無法處理,std :: cin進入“失敗”狀態它無法處理的輸入留在輸入流上。
std :: cin將忽略所有輸入,直到清除“fail”狀態:std :: cin.clear()
直接讀取數字的例程應該:
讀入數字
檢查輸入流是否仍然有效
如果輸入流不好(!std :: cin)
- 調用std :: cin.clear()將流從“失敗”狀態中取出。
- 從流中刪除導致問題的輸入:std :: cin.ignore(...)
- 如果適當,再次獲取輸入或以其他方式處理錯誤
更多信息: http : //www.augustcouncil.com/~tgibson/tutorial/iotips.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.