[C++]在 cin 後呼叫 getline 所遇到的問題
在 C++ 中,使用 cin 讀資料後,再用 getline 讀字串,就會遇到 buffer 沒有清空的問題。例如底下的程式碼:
這個例子中,程式先讀一個整數,將之放入 value 變數中。接著讀 value 個字串。所以要是 value 為 2 時,應該就要讀取 2 個字串。但在這個例子中,很奇怪就只會讀 1 個字串。
為什麼??
仔細看底下的輸出,我們會發現 string 1 是一個「空字串」!而 hello world 才是我們真正輸入的那個字串。那麼這個空字串是什麼?
它其實是個 new line,即 \n,或者說是一個 endl。
事情是這樣的。在第 8 行中,我們的程式碼要讀取一個整數:
cin >> value;
然後我們在鍵盤上鍵入 2,然後敲一個 enter。
這個時候,我們的電腦其實得到的是底下的資訊:
緩衝區中有一個 2,還有一個斷行。
那第8行再讀時,只會把 2 讀出來(因為我們要求讀一個整數,而 endl 不是整數,所以不會被讀出來)。
所以最後,緩衝區中會遺留一個 endl 在那兒。於是下次我們呼叫 getline 時,由於 C++ 偵測到緩衝區中還有資料,所以會先把那個 endl 讀出來。這就是為什麼我們只能讀到一個字串的原因。
那怎麼辦?
解決的方法有很多,最常見的有兩個:
這兩種作法都是把緩衝區清空,差別在於方法一需要多宣告一個字串變數。我個人是習慣方法2囉。
底下附上程式碼:
方法1:
方法2:
額外一題,這兒呼叫的 ignore 是一個預設的版本,它的運作方式是這樣的:清空緩衝區,直到底下的兩個條件,其中一個滿足為止!
上例中,使用者手殘,多輸入了一個 + (別笑,有時候打字快,總是會發生這種事)。這個時候由於 ignore 只清空一個字元,所以它會把 + 清掉,但是還是把 newline 留著,所以我們的程式還是會讀到那個 newline。
解法是要求 ignore 多清一些字元,程式碼示範如下:
上面的程式碼中,ignore 需要兩個參數,第1個參數要求 ignore 清空 1000 個字元。第2個參數要求 ignore 清空緩衝區,直到遇到 \n (new line)。這兩個要求只要其中之一滿足,ignore 就會停止。
有關 cin 和 getline 的問題,網路上有許多的討論,底下列了一些參考文獻,寫得很清楚,大家可以參考:
stackoverflow 的文章:cin and getline skipping input
ignore 的使用方式
這個例子中,程式先讀一個整數,將之放入 value 變數中。接著讀 value 個字串。所以要是 value 為 2 時,應該就要讀取 2 個字串。但在這個例子中,很奇怪就只會讀 1 個字串。
為什麼??
仔細看底下的輸出,我們會發現 string 1 是一個「空字串」!而 hello world 才是我們真正輸入的那個字串。那麼這個空字串是什麼?
它其實是個 new line,即 \n,或者說是一個 endl。
事情是這樣的。在第 8 行中,我們的程式碼要讀取一個整數:
cin >> value;
然後我們在鍵盤上鍵入 2,然後敲一個 enter。
這個時候,我們的電腦其實得到的是底下的資訊:
緩衝區中有一個 2,還有一個斷行。
那第8行再讀時,只會把 2 讀出來(因為我們要求讀一個整數,而 endl 不是整數,所以不會被讀出來)。
所以最後,緩衝區中會遺留一個 endl 在那兒。於是下次我們呼叫 getline 時,由於 C++ 偵測到緩衝區中還有資料,所以會先把那個 endl 讀出來。這就是為什麼我們只能讀到一個字串的原因。
那怎麼辦?
解決的方法有很多,最常見的有兩個:
- 在 cin 後,要是我們知道要呼叫 getline,那就「多呼叫一次 getline」,把緩衝區清空。
- 呼叫 cin.ignore() 把緩衝區清空。
這兩種作法都是把緩衝區清空,差別在於方法一需要多宣告一個字串變數。我個人是習慣方法2囉。
底下附上程式碼:
方法1:
方法2:
額外一題,這兒呼叫的 ignore 是一個預設的版本,它的運作方式是這樣的:清空緩衝區,直到底下的兩個條件,其中一個滿足為止!
- 清空 1 個字元。
- 讀到 endl。
前述兩個條件,只要有一個滿足,那 ignore 就會停止所有的動作了。
條件 2 比較容易想像,本來 ignore 就是要清空緩衝區,直到遇到 endl 為止。條件 1 比較神奇,為什麼只清空 1 個字元?沒法子,這是人家工程師預設好的。就照規定來囉。
要是使用預設的版本時,有時候遇到使用者「手殘」,那就有問題了。舉例如下:
上例中,使用者手殘,多輸入了一個 + (別笑,有時候打字快,總是會發生這種事)。這個時候由於 ignore 只清空一個字元,所以它會把 + 清掉,但是還是把 newline 留著,所以我們的程式還是會讀到那個 newline。
解法是要求 ignore 多清一些字元,程式碼示範如下:
上面的程式碼中,ignore 需要兩個參數,第1個參數要求 ignore 清空 1000 個字元。第2個參數要求 ignore 清空緩衝區,直到遇到 \n (new line)。這兩個要求只要其中之一滿足,ignore 就會停止。
有關 cin 和 getline 的問題,網路上有許多的討論,底下列了一些參考文獻,寫得很清楚,大家可以參考:
stackoverflow 的文章:cin and getline skipping input
ignore 的使用方式
留言
張貼留言