[英]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
標志傳遞給gcc
或clang++
。 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.