本文首先給出對”非規範輸入“一詞的定義:指用戶沒有按照程序設計者的期望規範而產生的輸入。
例如,程序要求輸入數字,用戶卻輸入了字母,而程序設計之初卻只考慮了對數字的處理;並沒有考慮到對字母的處理,於是在用戶輸入字母時,就有可能引發程序的錯誤執行乃至崩潰。
場景1:
輸入數字,判斷是否爲特定數字,但用戶非規範輸入了非數字如字母等。
代碼:
#include <iostream>
using namespace std;
int main(){
int a;
while(a != 1) {
cin >> a;
cout << "not a" << endl;
}
return 0;
}
循環判斷a是否爲1,若不爲1,彈出提示。
運行:
如圖依次輸入4 3 2 1,運行正常。
但是如果遇到非規範輸入:
如圖輸入a,程序陷入輸出"not 1"的死循環中。
分析:
因爲語句int a = 0;將a聲明成數值型,則語句cin >> a;將會從緩衝區中提取一個數值賦值給a。
但是,用戶輸入字母a後,緩衝區中並沒有數值,只有字母a和一個回車符。
因此,語句cin >> a;將不會從此緩衝區中提取內容,也不會改變緩衝區的內容,緩衝區裏就一直是字母a和一個回車符。
如何解決這個問題呢?每次新的cin命令執行時,殘留在緩衝區中的內容都會干擾程序的正確執行,於是,不妨在每次cin前,先將緩衝區清空,即使用cin.clear()和cin.sync()命令。
cin.sync()命令用於清輸入流(緩衝區)。
cin.clear()命令用於清標誌位,包括failbit標誌位。
代碼修改:
#include <iostream>
using namespace std;
int main(){
int a = 0;
while(a != 1) {
cout << "not 1" << endl;
//增加以下兩行代碼
cin.clear();
cin.sync();
//增加以上兩行代碼
cin >> a;
}
cout << "is 1" << endl;
return 0;
}
運行:
輸入非數字的a a b c ! 程序就不會陷入死循環了。
場景2:
循環使用stoi()函數將用戶輸入的數字字符串轉換爲數字類型,但用戶非規範輸入了字母等。
代碼:
#include <iostream>
#include <string>
using namespace std;
int main() {
string a;
int i;
while(1) {
cout << "請輸入一串數字:";
cin >> a;
i = stoi(a);
cout << "您輸入的數字爲:" << i << endl;
}
return 0;
}
運行:
對一般的數字輸入,程序都能正常運行。
但是遇到用戶的非規範輸入abc時,程序就出錯崩潰了。
分析:
其實,在cmd中我們就可以看到這種錯誤的類型爲std::invalid_argument(無效實參),那麼我們就可以利用C++提供的try...catch...異常處理機制來解決。
使用try包含到可能觸發異常的代碼行,使用catch捕獲無效實參異常exception invalid argument,使用引用&。
代碼:
#include <iostream>
#include <string>
using namespace std;
int main() {
string a;
int i;
while(1) {
try {
cout << "請輸入一串數字:";
cin >> a;
i = stoi(a);
}
catch (exception& invalid_argument) {
cout << "輸入的不是數字。請檢查!" << endl;
continue;
}
cout << "您輸入的數字爲:" << i << endl;
}
return 0;
}
運行:
這樣,程序遇到用戶的非規範輸入時,就不會崩潰,而是輸出提示信息後,跳向下一輪循環,繼續執行。
參考資料:
cppconference
C++ Primer Plus