【C++筆記】一些輸入函數 cin, getline(), cin.get() 等
===
[TOC]
cin
---
這大家都知道,這是 C++ 的標準輸入物件,屬於 istream 類別。
基本語法不外乎就是透過鍵盤輸入將資料存入某個變數。
```cpp
int a;
cin >> a;
```
那其特性如下:
* 以空白(空格、Tab 縮排、換行)為分隔符號。
* 自動忽略前導空白字元(如輸入:`1 2 3 4 5`,每個數字間的空格都會忽略,並依序存入變數)
* 無法讀取含有空白字元的字串,如下範例:
```cpp
string name;
cin >> name;
// 輸入 John Doe
// name 只會得到 "John"
```
這是 cin 的缺點,要讀入完整的字串,則需要 `getline()`。
printf() / scanf()
---
雖然本文講輸入函數,但想說既然 C 有的東西,C++ 當然也繼承下去,就順便講一講 printf()。
相對於 cin / cout 來說,printf() / scanf() 的執行效率遠高於前者,因為在底層進行實作,接近硬體層面。
其基本語法如下:
`printf("字串格式化符號", 值1, 值2, ...)`
`scanf("字串格式化符號", &值1, &值2, ...)`
使用前先引入 `<cstdio>`,或是 `<stdio.h>`,或是也可以不用寫。
```cpp=
#include <cstdio>
using namespace std;
int main(){
int a;
scanf("%d", &a);
printf("%d", a);
return 0;
}
```
Output(輸入 2 輸出 2):
```
2
2
```
字串結合格式化符號:
```cpp=
#include <cstdio>
using namespace std;
int main(){
int a;
printf("請輸入:");
scanf("%d", &a);
printf("你所輸入的是:%d", a);
return 0;
}
```
Output:
```
請輸入:2
你所輸入的是:2
```
`&` 取出變數 a 的記憶體位址,用於告訴 scanf 要將輸入的東西存到哪裡。
以下是一些常用的格式化符號:
| 類型 | 符號 | 說明 |
| ----- | ---------- | ------------ |
| 整數 | `%d` | 10 進位整數 |
| | `%x`, `%X` | 16 進位(小寫/大寫) |
| | `%o` | 8 進位 |
| 字元 | `%c` | 單一字元 |
| 字串 | `%s` | 字元陣列 |
| 浮點數 | `%f` | 十進位浮點數 |
| | `%.nf` | 保留 n 位小數 |
| | `%e`, `%E` | 科學記號表示法 |
| 指標 | `%p` | 地址指標輸出 |
| 百分比符號 | `%%` | 輸出 `%` 本身 |
浮點數的格式化符號 `%.nf` 是比較常在考試中被拿出來講的東西:
```cpp=
#include <cstdio>
using namespace std;
int main(){
float a = 0.12345;
printf("%.2f", a); // 0.12345 只取小數點後兩位, 輸出即 0.12
return 0;
}
```
Output:
```
0.12
```
經典題:
```cpp=
#include <cstdio>
using namespace std;
int main(){
float a = 0.12345;
// %2.f 代表這個字串的總字元最小寬度為 2
printf("%2.f", a); // %2.f, 點後面沒東西預設就是 %2.0f
return 0;
}
```
Output:
```
0
```
輸出的 0 多了一個空格,因為 `%2.f` 的關係,要求總字元寬度至少要為 2,阿 0 只有一個字元,所以左邊補一個空格,就醬。
getline()
---
讀取整行字串,包含空格,直到遇到換行字元(\n)。
語法:
```cpp
string line;
getline(cin, line);
```
若 getline 前面有 cin 的話,如下:
```cpp
string a;
cin >> a;
getline(cin, line);
```
需要加上 `cin.ignore()`,去把前面 cin 留下的 `\n` 給忽略掉,避免影響到後續 `getline()` 讀取。
```cpp
string a;
cin >> a;
cin.ignore();
getline(cin, line);
```
cin.get()
---
讀取單一字元,含空格與 `'\n'`。
語法:
```cpp
char ch;
cin.get(ch);
```
特性:
* 不會忽略空白與換行,為 cin 的延伸版本。
* 也可寫成:`char ch = cin.get();`
限制輸入字元:
```cpp=
char str[20];
cin.get(str, 20); // 讀取最多 19 字元,含空格
cout << str << endl;
```
在後面多加一個整數參數,即可限制要輸入多少個字元,從輸入中讀取最多 `size-1` 個字元(含空格),直到讀到 `\n` 或到達上限為止。
另外很重要的就是他會在結尾加上 `'\0'` 字元,表示字串到此結束。
也不會讀取 `\n`,會留在輸入緩衝區,所以若要繼續用 getline() 或 cin.get() 的時候,就用 `cin.ignore()` 清除。
如果緩衝區已經滿了,會發生 failbit,可用 `cin.clear()` 清除。
另外 `cin.get()` 也可自訂結束字元(delimiter),預設為 `\n`。若遇到指定的結束字元會停止讀取,但不會把 delimiter 取走。
具體語法如下:
```
cin.get(char *buffer, int size, char delim)
```
其實就是多加第三個參數,然後指定結束字元。
cin.getline()
---
這是用來填入字元陣列(C-style string)的方法。
語法:
```cpp=
char buf[100];
cin.getline(buf, 100);
```
特性:
* 和 `getline()` 相同,可讀取整行(含空格),但需指定緩衝區的大小。
* 結尾自動加上 `\0` 表示字串結束,這是 C 語言的作法。
總結
---
### 1. cin
- 標準輸入物件,屬於 `istream` 類別。
- **特性**:
- 以空白(空格、Tab 縮排、換行)為分隔符號。
- 自動忽略前導空白。
- **無法讀取含空格的字串**,例如輸入 "John Doe" 只會取得 "John"。
- 適用於基本輸入(整數、字串無空白等情形)。
---
### 2. getline()
- **用於讀取整行字串**(包含空格),直到 `\n` 為止。
- 若前面有用 `cin`,需加 `cin.ignore()` 清除殘留的 `\n`。
- 語法:`getline(cin, line);`
- line 是字串型態
---
### 3. cin.get()
- 可讀取單一字元,**含空白與換行**。
- 語法有兩種:
- `cin.get(ch);`
- `char ch = cin.get();`
- 也可限制讀取字元數:`cin.get(buffer, size);`,適用於 C-style 字串。
- 可設定自訂的結束字元(delimiter),為 cin.get() 的第三個參數。
---
### 4. cin.getline()
- 用於 **C-style 字元陣列** 的整行輸入。
- 語法:`cin.getline(buf, size);`
- 功能與 `getline()` 類似,但需指定緩衝區大小。
- 自動在結尾加上 `\0` 字元。
---
### 5. scanf() / printf()(C 語言)
- 執行效率較高,底層更貼近硬體。
- 格式化控制更細緻,如 `%d`、`%f`、`%.2f` 等。
- 使用需引入 `<cstdio>`、`<stdio.h>`,也可以不用加。
- 別忘了用 scanf() 時,要存入的變數都要在前面加上 `&` 取址運算子。
---
### 結語
- 各輸入方式適用場景不同:
- `cin`:單一基本型態。
- `getline()`:讀取整行含空白的 `string`。
- `cin.get()` / `cin.getline()`:操作細緻、支援 C-style 字元陣列。
- `scanf()`:效率高、格式化明確,但較不安全(如緩衝區溢位問題)。
參考資料
---
[C++中cin、cin.get()、cin.getline()、getline()、gets()等函数的用法 - flatfoosie - 博客园](https://www.cnblogs.com/flatfoosie/archive/2010/12/22/1914055.html)
[cin get() in C++ with Examples | geeksforgeeks](https://www.geeksforgeeks.org/cin-get-in-c-with-examples/)
[printf 與 scanf](https://openhome.cc/Gossip/CGossip/PrintfScanf.html)
[如何在 C++ 中使用 scanf() & printf()_c++scanf函数-CSDN博客](https://blog.csdn.net/bjxqmy/article/details/98251253)