在 Visual Studio 2010 中撰寫 C++ Primer 範例時,發現兩個函數調用順序不同會導致程式行為截然不同:先呼叫 two_num() 再呼叫 plus() 正常;調換順序後,第二個函數無法讀取輸入。這不只是順序問題,而是 istream 狀態機制的經典陷阱。
// 情況一:正常
two_num(); // 讀取兩數求和
plus(); // 讀取多數求和(Ctrl+Z 結束)
// 情況二:異常
plus(); // 讀取多數求和(Ctrl+Z 結束)
two_num(); // 無法讀取輸入,直接結束
plus() 使用 while (std::cin >> value) 迴圈,遇到 EOF (Ctrl+Z) 或非整數輸入 時,std::cin 會進入失效狀態(failbit 或 eofbit 被置位)。一旦進入失效狀態,後續所有 >> 操作都會直接失敗,不再讀取資料。
正常狀態 (goodbit)
↓ 讀到 EOF / 非法輸入
失效狀態 (failbit | eofbit)
↓ 任何 >> 操作
直接返回 false,不讀取資料
cin 保持良好狀態 → plus() 正常讀取直到 EOFcin 失效 → two_num() 嘗試讀取時 cin >> v1 直接失敗,跳過輸入plus();
std::cin.clear(); // 清除 failbit/eofbit
std::cin.ignore(INT_MAX, '\n'); // 清緩衝區殘留字符
two_num(); // 可正常讀取
將 while (std::cin >> value) 改為特定哨兵值:
int plus() {
int sum = 0, value;
std::cin >> value;
while (value != 0) { // 輸入 0 結束,而非 EOF
sum += value;
std::cin >> value;
}
std::cout << "Sum is: " << sum << std::endl;
return 0;
}
優點:不依賴 EOF,流狀態始終良好,函數可任意順序調用。
std::cin.clear() 並清理緩衝區std::cin.fail() / std::cin.eof() 並處理InputHandler 類,統一管理輸入狀態函數調用順序改變行為,本質是 istream 的狀態機特性:EOF 會永久污染流狀態。理解 goodbit/failbit/eofbit 轉換邏輯,採用哨兵值替代 EOF,即可寫出健壯的交互式輸入代碼。