C++問題集合

本文最後更新於:2022年4月17日 下午

C++問題集合

在 cin>> 後呼叫 getline 會遇到 buffer 沒有清空

總結:

多次使用cin>>,cin.getline(), getline()

  • 每次使用了cin>>之後,都會在緩衝區中多出來一個換行符(因為會敲下enter,代表輸入資料時,一個 \n會被插入到輸入流之中 ),所以每次使用了cin>>之後都需要利用「cin.ignore()」將多出來的換行符處理掉;

如果連續兩次都是cin>>,就不需要將多出來的換行符去掉了。

因為cin的時候,並不是只要讀取到換行符就執行完cin,而是必須要讀取到相對應的類型的內容從鍵盤敲入,才會真正執行完cin

  • cin不允許輸入為空
    • 所以cin>>在等待鍵盤敲入時,就算先敲換行符,cin>>語句也不會執行結束。
  • 簡單來說,cin一定要吃到資料,並且在遇到換行符時結束(不會吃進換行符)

但是cin.getline()函數和getline()函數,它們都是以換行符作為唯一的標準

  • getline()允許輸入為空,也就是說直接一個換行符就結束,
    • 也可以吃進 「包含空白符的字串」,直到遇到換行符

img

原因:

cin >> value; cin會在遇到換行符時停止,這個換行符會被留在鍵盤緩衝區中

而 「從鍵盤讀取數值的輸入語句,只在鍵盤緩衝區為空時,才會等待用戶輸入值」

然後我們在鍵盤上鍵入 2,然後敲一個 enter。

這個時候,我們的電腦其實得到的是底下的資訊:

緩衝區中有一個 2,還有一個斷行。
那第8行再讀時,只會把 2 讀出來(因為我們要求讀一個整數,而 endl 不是整數,所以不會被讀出來)。

所以最後,緩衝區中會遺留一個 endl 在那兒。於是下次我們呼叫 getline 時,由於 C++ 偵測到緩衝區中還有資料,所以會先把那個 endl 讀出來。這就是為什麼我們只能讀到一個字串的原因。

解決的方法有很多,最常見的有兩個:

  1. 在 cin 後,要是我們知道要呼叫 getline,那就「多呼叫一次 getline」,把緩衝區清空。
1
2
3
cin >> value;
string strtmp;
getline(cin, strtmp); //strtmp 只是把緩衝區清空,沒有其他的作用
  1. 使用cin.get()

    • get 函數讀取單個字符,包括任何white space字符
    1
    2
    3
    char ch;
    cin.get(ch);//法一
    cin.get();//法二
  2. 呼叫 cin.ignore() 把緩衝區清空。

1
2
cin >> value;
cin.ignore(); //呼叫 ignore 忽略緩衝區的資料

該預設版本的ignore 會清空緩衝區,直到底下的兩個條件,其中一個滿足為止!

  1. 清空 1 個字元。
  2. 讀到 endl。

所以如果多了一些意外出現的字元,還是會無法把endl清理掉!

改良版本:

1
2
3
4
5
6
7
cin >> value;
/**ignore 的運作方式如下:
* 清空 1000 個字元(第1個參數),
* 或是清空緩衝區,直到遇到 \n (new line)
* 那就停止
*/
cin.ignore(1000, '\n');

參考資料:

[C++]在 cin 後呼叫 getline 所遇到的問題 (justimchung.blogspot.com)

(6条消息) C++中的cin, cin.getline, getline等混合使用时不能输入直接执行下一行的问题_Leonardo Liu的博客-CSDN博客_c++ cin getline

endl\n的區別

\n只代表換行的轉義字符;

  • 輸出’\n’是實際輸出了的’\10’,往輸出流裡添加了訊息

endl除了代表換行,還緊跟著清出緩衝槽

  • endl是C++中使用的io流換行
  • 輸出endl不會往輸出流裡添加東西,只會簡單的刷新流並換行

參考資料:

https://blog.csdn.net/u011675745/article/details/51939094

命名空間namespace

C++標準為了和C區別開,也為了正確地使用名稱空間,規定標頭檔案不使用字尾.h*當使用時,該標頭檔案沒有定義全域性名稱空間,必須使用namespace std,指明在哪裡的名稱空間,這樣才能使用類似於cout這樣的C++識別符號。

  • 如果你的應用程式是多個團隊共同合作,如果沒有定義名稱空間,名稱預設都是位於全域名域空間,以類別定義來說,那麼若 A 部門寫了個 Account 類別,B 部門寫了個 Account 類別,當他們要將應用程式整合時,就會發生名稱衝突的問題。

https://www.itread01.com/content/1547346090.html

由於namespace的概念,使用C++標準程式庫的任何識別符號時,可以有三種選擇:

  1. 直接指定識別符號

例如:

std::iostream而不是iostream。完整語句如下: std::cout << std::hex << 3.4 << std::endl;

  1. 使用using關鍵字

例如:

using std::cout; using std::endl; using std::cin; 以上程式可以寫成如下程式碼:

using std::cout <<using std::hex << 3.4 <<using std:: endl;

  1. 使用using namespace std

例如:

#include

#include

#include

using namespace std;

這樣名稱空間std內定義的所有識別符號都有效(曝光)。就好像它們被宣告為全域性變數一樣。