C++ cin判斷輸入結束(讀取結束)

2020-07-16 10:05:23
cin 可以用來從鍵盤輸入資料;將標準輸入重定向為檔案後,cin 也可以用來從檔案中讀入資料。在輸入資料的多少不確定,且沒有結束標誌的情況下,該如何判斷輸入資料已經讀完了呢?

從檔案中讀取資料很好辦,到達檔案末尾就讀取結束了。從控制台讀取資料怎麼辦呢?總不能把控制台關閉吧?這樣程式也執行結束了!

其實,在控制台中輸入特殊的控制字元就表示輸入結束了:
  • 在 Windows 系統中,通過鍵盤輸入時,按 Ctrl+Z 組合鍵後再按確認鍵,就代表輸入結束。
  • 在 UNIX/Linux/Mac OS 系統中,Ctrl+D 代表輸入結束。

不管是檔案末尾,還是 Ctrl+Z 或者 Ctrl+D,它們都是結束標誌;cin 在正常讀取時返回 true,遇到結束標誌時返回 false,我們可以根據 cin 的返回值來判斷是否讀取結束。

cin 判斷控制台(鍵盤)讀取結束

輸入若干個正整數,輸出其中的最大值,程式該如何編寫?
#include <iostream>
using namespace std;
int main()
{
    int n;
    int maxN = 0;
    while (cin >> n){  //輸入沒有結束,cin 就返回 true,條件就為真
        if (maxN < n)
            maxN = n;
    }
    cout << maxN <<endl;
    return 0;
}
在 Windows 下執行該程式,先輸入以下整數:

10
30
93
206
8

然後在按下 Ctrl+Z 組合鍵(可以在當前行,也可以在新的一行),接著按下確認鍵,輸入就結束了,此時 cin 返回 false,迴圈結束,得到了最大值。

完整的輸入輸出結果如下所示:

10↙
30↙
93↙
206↙
8↙
^Z↙
206

表示確認鍵,^Z表示 Ctrl+Z 組合鍵。

cin 判斷檔案讀取結束

如果將標準輸入重定向為某個檔案,如在程式開始新增freopen("test.txt", "r", stdin);語句,或者不新增上述語句,但是在 Windows 的“命令提示字元”視窗中輸入:

mycin < test.txt  //假設編譯生成的可執行檔案的名字為 mycin.exe

則都能使得本程式不再從鍵盤輸入資料,而是從 test.txt 檔案輸入資料(前提是 test.txt 檔案和 mycin.exe 在同一個資料夾中)。在這種情況下,test.txt 檔案中並不需要包含 Ctrl+Z,只要有用空格或回車隔開的若干個正整數即可。

cin 讀到檔案末尾時,cin>>n就會返回 false,從而導致程式結束。例如,假定 test.txt 檔案中的內容如下所示:

112
23123
34 444 55
44

對於前面的程式碼,在“命令提示字元”視窗中先 cd 到 mycin.exe 所在目錄,然後輸入mycin < test.txt,則程式的輸出是:

23123


下面是筆者實操演示圖:
將輸入重定向到文件

答疑解惑

在《C++過載<<和>>》一節中我們提到過 istream 類將>>過載為成員函數,而且這些成員函數的返回值是 cin 的參照。準確地說,cin>>n的返回值的確是 istream & 型別的,而 while 語句中的條件表示式的返回值應該是 bool 型別、整數型別或其他和整數型別相容的型別,istream & 顯然和整數型別不相容,為什麼while(cin>>n)還能成立呢?

這是因為,istream 類對強制型別轉換運算子 bool 進行了過載,這使得 cin 物件可以被自動轉換成 bool 型別。所謂自動轉換的過程,就是呼叫 cin 的 operator bool() 這個成員函數,而該成員函數可以返回某個標誌值,該標誌值在 cin 沒有讀到輸入結尾時為 true,讀到輸入結尾後變為 false。對該標誌值的設定,在 operator <<() 成員函數中進行。

如果 cin 在讀取過程中發生了錯誤,cin>>n這樣的表示式也會返回 false。例如下面的程式:
#include <iostream>
using namespace std;
int main()
{
    int n;
    while (cin >> n)
        cout << n << endl;
    return 0;
}
程式本該輸入整數,如果輸入了一個字母,則程式就會結束。因為,應該讀入整數時卻讀入了字母也算讀入出錯。