簡體   English   中英

試圖了解cin的行為

[英]Trying to understand cin behavior

我正在編寫從stdin獲取(巨大)輸入流並將其讀入浮點向量的軟件。 我想捕獲這種情況,即流包含逗號之類的字符,或者不接受它,或者只是忽略了無法解析為float的所有內容(以更容易實現的為准,我沒有優先選擇)。 我注意到以下行為:當我打電話時

echo "1.4, -0.7 890 23e-3" | ./cintest

這個版本

#include <iostream>
using std::endl;
using std::cin;
using std::cout;

int main ( int argc, const char* argv[] ){
    float val;
    while (cin >> val) {
        cout << val << endl;
    }
    return 0;
}

版畫

1.4

而這個版本

#include <iostream>
using std::endl;
using std::cin;
using std::cout;

int main ( int argc, const char* argv[] ){
    float val;
    while (cin) {
        cin >> val;
        cout << val << endl;
    }
    return 0;
}

版畫

1.4
0

沒有逗號,第一個打印

1.4
-0.7
890
0.023

而第二個打印

1.4
-0.7
890
0.023
0.023

有人可以解釋一下這是怎么回事嗎?

您的代碼的第一個版本

    while (cin >> val) {

嘗試解析浮點數, 然后檢查流狀態是否良好。 (特別是,它調用operator>>進行提取,這將在出錯時設置failbit ,然后使用bool轉換來測試failbit )。

所以,如果流狀態是壞的(因為它無法轉換,為float),不進入循環體。 因此,它在第一次轉換失敗時終止。

第二版

    while (cin) {
    cin >> val;

檢查流狀態是否良好(這只會告訴您先前的轉換已成功),然后嘗試解析浮點數,然后假定未檢查就成功了。 在使用float值之前,應該在轉換后檢查流狀態,在這種情況下,float值是前一次迭代遺留下來的。

在正確的實現中,當轉換失敗時,您應該檢查一下fail()是否為true但eof()是否為false(即,轉換是由於文件末尾以外的某種原因而失敗)。 在這種情況下,請使用ignore()放棄輸入-您可以要求使用空格(並忽略直到下一個空格),或者僅忽略一個字符並重試。

請注意,上面鏈接的ignore文檔包括帶有正確錯誤處理的示例代碼。 如果我們選擇在轉換失敗時跳過單個字符,則您的代碼將變為:

for(;;) {
    float val;
    std::cin >> val;

    if (std::cin.eof() || std::cin.bad()) {
        break;
    } else if (std::cin.fail()) {
        std::cin.clear(); // unset failbit
        std::cin.ignore(1); // skip next char
    } else {
        std::cout << val << '\n';
    }
}

您的結果有難同的做>>失敗。

在兩個版本中,您都讀取了值並到達了逗號(或EOF)。 讀顯然失敗了,因為,和EOF都不是有效整數>>可以解析。 因此>>的返回值(流本身)將轉換為false ,並且您在第一個版本中退出循環(這是它的工作方式)。

但是,在第二個版本中(這通常不是您應該做的),您仍在打印出最終以val任何值。 在C ++ 11之前的C ++中, val保持不變。 因為C ++ 11 >>在失敗時寫入0

TL; DR:您的第二個版本將循環停止到很晚,並寫入一遍垃圾。

這是因為在第二個中您有一個錯誤。

您應該始終檢查格式化的輸入operator>>真正起作用。

所以這段代碼:

    cin >> val;
    cout << val << endl;

應寫為:

    if (cin >> val) {
        cout << val << endl;
    }

如果operator>>失敗。 然后,它將在流上設置失敗位之一,而不將任何值放入val 因此,無需打印val因為沒有放入任何內容。

這就是為什么您的第二個版本在沒有剩余數據可讀取時會打印垃圾的原因。 讀取失敗,然后打印出一個值。 然后,您嘗試重新啟動循環(失敗)。

第一個正常工作。

while (cin >> val) {
    cout << val << endl;
}

因為您讀取了一個值,所以在進入循環之前請先檢查讀取是否有效。

std :: cin是std :: istream的實例

如果在任何時候出現逗號或任何無效的數據類型,操作符>>都會失敗。 因此,您的代碼將顯示最后一個已知的值“ val”。

此處鏈接是“ std :: istream >>”的參考

http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/

暫無
暫無

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

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