2013-10-29 56 views
0

更具體地說,我想確保這個類型是double(或者int/float)。我搜索了近乎和遠處,並發現幾乎沒有非嚴格的解決方案。我只想使用我完全可以理解的代碼,作爲C++的一個完整的初學者。如何檢查在cin上讀取的數據類型?

在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; 

這不起作用。循環繼續進行雙打輸入,但一旦我輸入的東西不是雙倍的代碼只是停止,並沒有前進。我很漂亮。有什麼建議麼?

+1

'typeid(x)'取決於'x'的*類型*,它由您聲明'x'首先確定的內容決定。 – juanchopanza

+0

你如何區分輸入的int,float和double?例如,如果我輸入2.0,那麼你認爲它是什麼? –

+0

juanchopanza:那麼我該如何檢查用戶的輸入是不是雙精度? –

回答

3

用戶沒有「輸入變量」。她輸入一個字符串。當提供一個浮點變量時,運算符>>會嘗試將此字符串解釋爲浮點數字的文本表示形式。

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

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

完美地工作,謝謝寶貝。 –

0

如果x被聲明爲雙,你如果病情就會失敗,因此while循環被打破

+1

不是嗎? (typeid(x)!= typeid(float)&& typeid(x)!= typeid(double)&& typeid(x)!= typeid(int))如果x是double,則返回true。 –

+0

再次閱讀您的陳述,您將所有內容與邏輯AND相結合,您的條件之一是x不應該是double類型。如果它是double類型的,這個條件不能被滿足,因此整個條件,因爲ANDed,評估爲false。 –

0

這裏有幾種解決方案。我會發布其中2個。由於stod函數,第一個解決方案需要C++ 11標準。你可以這樣做,通過-std=c++11標誌gccclang++。微軟編譯器默認啓用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。這是因爲stod函數的行爲如下所示:stod reference

請注意,此解決方案只允許讀取每行兩個。

解決方案2。直接使用cin >> input_double閱讀。這可能會失敗。請注意,iostream s在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,停在你好。之後,failbit被設置。我們清理故障位以便能夠繼續讀取直到行結束。既然你好被認爲是「垃圾」,因爲我們想讀雙打,所以我們用getline清理它,我們可以再次使用cin沒有麻煩。