簡體   English   中英

如何檢查從cin讀取的數據類型?

[英]How do I check the type of data read on cin?

更具體地說,我要確保此類型為double(或int / float)。 我搜索了很多,發現了幾乎為零的非嚴格解決方案。 作為C ++的完整入門者,我只想使用我能完全理解的代碼。

在Java中,我可以簡單地執行以下操作:

ArrayList<Double> data = new ArrayList<Double>();
Scanner in = new Scanner(System.in);
while (in.hasNextDouble()) {
        double x = in.nextDouble();
        data.add(x); 
        n += 1;      
        sum += x;    
}  
double average = sum / n; 

C ++顯然是另外一個故事。 這是我嘗試過的:

vector<double> data;
while (looping) 
{
    cin >> x;
    if (typeid(x) != typeid(float) && typeid(x) != typeid(double) &&
        typeid(x) != typeid(int))
            {looping = false; break;}
    data.push_back(x);
    n += 1;
    sum += x;
}
double average = sum / n;

這行不通。 輸入雙精度數后,循環繼續進行,但是一旦我輸入的不是雙精度數,代碼就會停止並且不會繼續前進。 我非常垂頭喪氣。 有什么建議么?

用戶不“輸入變量”。 她輸入一個字符串。 並且,運算符>>當提供浮點變量時,會嘗試將此字符串解釋為浮點數的文本表示形式。

它可能成功也可能不成功:在Java中,失敗將導致nextDouble()引發異常。 在C ++中,流操作不會拋出異常。 相反,失敗意味着cin.good()將開始返回false

float x;
cin >> x;
while (cin.good()) 
{   
    data.push_back(x);
    n += 1;
    sum += x;
    cin >> x;
}

如果x被聲明為double,則您的if條件將失敗,因此while循環中斷

您在這里有幾種解決方案。 我將發布其中的2個。 由於stod功能,第一個解決方案需要c ++ 11標准。 您可以通過將-std=c++11標志傳遞給gccclang++ Microsoft編譯器默認情況下啟用c ++ 11。

解決方法1 它包括一直通過cin >> input_string讀取字符串,並使用標准c ++ 11函數stod stod代表字符串加倍。 如果stod無法解析double ,它將拋出std::invalid_argument異常。

此解決方案將是這樣的:

#include <iostream>
#include <vector>
#include <numeric>
#include <string>
#include <stdexcept>

using namespace std;


int main() {
   vector<double> vec;
   string input;
   try {
      while (getline(cin, input)) {
         vec.push_back(stod(input));

      }
   }
   catch (std::invalid_argument &) {
      cout << "Invalid argument caught\n";
      //Failed to parse a double
   }
   //If pressed Ctrl+D (in linux, which sends EOF), failbit and eofbit are set
   //If it is through invalid_argument the way the loop was exit, then,
   //eof and failbit are not set and cin can be used without clearing.
   double average = accumulate(vec.begin(), vec.end(), 0.0)/vec.size();
   cout << "EOF: " << cin.eof() << endl;
   cout << "Fail: " << cin.fail() << endl;

   //Clean eof and failbit to be able to use cin again
   cin.clear();
   cout << "EOF after cleaning: " << cin.eof() << endl;
   cout << "Fail after cleaning: " << cin.fail() << endl;

   cout << average << endl;

}

編輯:我測試過,當您每行放置多個數字時,它只會得到第一個而不拋出std::invalid_argument 僅當以非雙std::invalid_argument開頭的行開始時才拋出std::invalid_argument 這是因為stod函數的行為如下: stod reference

請注意,此解決方案僅允許每行讀取一個雙精度數。

解決方案2 直接使用cin >> input_double閱讀。 這可能會失敗。 請注意,默認情況下, iostream在c ++中不使用exceptios。 您可以使用api激活它們,但我不建議您這樣做,因為您可以在本地管理所有錯誤處理。

您可以讀取任意數量的雙打,並用任何空格隔開:

#include <iostream>
#include <vector>
#include <numeric>
#include <limits>

using namespace std;


int main() {
   double x = 0.0;
   vector<double> data;

   //cin will fail to read the first non-double in the input.
   //You can input as many doubles as you wish. Spaces will
   //be ignored. At the first non-double, cin will fail to read
   //and will exit the loop, setting istream::failbit.
   //Alternatively, you can send EOF (Linux is Ctrl+D) and the loop also will finish.
   while (cin >> x) {
      data.push_back(x);

   }
   double average = accumulate(data.begin(), data.end(), 0.0)/data.size();

   //If you wanted to use again cin, you should:
   //1. Clear failbit. You can do like this:
   cin.clear();

   //2. Cleaning the remaining input. Will stop when finding end of line.
   string rubbish;
   geline(cin, rubbish);
   //cin is usable here again if you need it and with the input clean already.


   cout << average << '\n';
}

您可以在輸入的一行中給出以下內容:

1 2.4 -38.7 5.8 28.9你好。

會發生什么? 循環將消耗到28.9,並立即停止。 之后,設置故障位。 我們清除故障位,以便能夠繼續讀取直到行尾。 由於hello被視為“垃圾”,因為我們想讀取雙打,因此我們使用getline對其進行了清理,因此可以再次使用cin而不會遇到麻煩。

暫無
暫無

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

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