簡體   English   中英

c ++驗證數字並停止無限循環

[英]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' );

插入字母時會發生這種情況:

  1. operator>>從流中提取字符並嘗試將它們轉換為數字;
  2. 它在轉換中失敗,因此它將流狀態設置為ios::failbit並返回; opt可能不受影響(標准將這些東西委托給語言環境庫,這是我從未真正理解的C ++區域 - 對於勇敢的,它是在§22.2.2.1.2);
  3. 因為它返回並且(可能) opt保持原樣,循環繼續;
  4. 當執行返回到std::cin >> opt; operator>>看到狀態仍然是ios::failbit ,所以它甚至都沒有嘗試提取任何東西;
  5. 轉到3。

要解決此問題,您應該清除錯誤狀態並從輸入緩沖區中刪除“錯誤”字符。 既然你可能不想將所有代碼添加到每個cin>> ,那么創建一個處理這個常見問題的函數是很有用的。 就個人而言,我創建了這個已被證明有用多次的AcquireInput.hppAcquireInput.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()

直接讀取數字的例程應該:

  1. 讀入數字

  2. 檢查輸入流是否仍然有效

  3. 如果輸入流不好(!std :: cin)

    1. 調用std :: cin.clear()將流從“失敗”狀態中取出。
    2. 從流中刪除導致問題的輸入:std :: cin.ignore(...)
    3. 如果適當,再次獲取輸入或以其他方式處理錯誤

更多信息: http//www.augustcouncil.com/~tgibson/tutorial/iotips.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM