Try   HackMD

進階輸入輸出與資料型態

這篇來講講實用的輸入以及輸出技巧。由於很多輸入輸出都跟使用的資料型態有關,所以也會帶到一點資料型態的部分

常用資料型態的輸入輸出

整數

資料大小範圍

資料型態 範圍 估計值
int
2,147,483,648
~
2,147,483,647
±2×109
long long
9223372036854775808
~
9223372036854775807
±9×1018
__int128
2127
~
21271
很大

使用範例

int a;
cin >> a;
cout << a << endl;
long long b;
cin >> b;
cout << b;

__int128 無法被直接輸入輸出,通常是運算較大的數字才會用到

浮點數

浮點數就是指有小數點的數字

資料型態 範圍 精度
float
3.4e±38
小數點後七位
double
1.7e±308
小數點後十五位

cin/cout 範例

float a;
double b;
cin >> a >> b;
cout << a << ' ' << b;

小數點後第幾位

記得要有標頭檔 <iomanip>

// #include <iomanip>
double n = 3.1415;
cout << fixed << setprecision(2) << n;

控制小數

記得要有標頭檔 <cmath>
ceil() : 無條件進位
floor() : 無條件捨去
round() : 四捨五入

// #include <cmath>
double x = 3.1415926535
cout << ceil(x) << ' ';
cout << floor(x) << ' ';
cout << round(x);

字元與字串

一個 char 變數就是儲存 ASCII 表裡面的一個整數編號

使用範例

char c = 'c';
cout << (int)c << endl;
cout << (char)66 << endl;
c -= 2;
cout << c << endl;

輸出

99
B
a

字串

這裡使用 C++ 的方法來處理字串,C 語言的可以看這篇
首先要先引入標頭檔 <string>

cin/cout 範例

// #include <string>

string s;
cin >> s;
cout << s;

讀入整行範例

getline() 可以讀入整行

// #include <string>

string s;
getline(cin, s);
cout << s;

cin/getline 範例

要注意 getline() 會把 '\n' 處理掉,但是 cin 不會處理掉 '\n' ('\n' 還是存在輸入流裡面)。因此兩者混著使用時須要再多一行 getline() 來處理掉 '\n'

string s, tmp;
int n;
cin >> n;
getline(cin, tmp); // 這一行專門把 '\n' 給處理掉
getline(cin, s);

數字與字串做轉換

string s = "123";
int n = stoi(s);
cout << n << '\n';
cout << to_string(n) << '\n';

stringstream 處理空白

記得要有標頭檔 <sstream>

// #include <sstream>
stringstream ss;
string tmp, s = "12 31415 15 1357";
int arr[10], n = 0;

ss << s; // 將字串丟入 stringstream
while (ss >> tmp) // 一個一個將字串丟入 tmp
    arr[n++] = stoi(tmp); // 把字串轉成數字、再存進 arr[]

for (int i = 0; i < n; i++) // 印出來
    cout << arr[i] << '\n';

輸出格式調整

向右對齊

記得要有標頭檔 <iomanip>

使用範例

cout << setw(4) << 3 << setw(4) << 12 << '\n';
cout << setw(4) << 213 << setw(4) << 8 << '\n';

輸出

   3  12
 213   8

向左對齊

記得要有標頭檔 <iomanip>

使用範例

cout << left << setw(4) << 3 << left << setw(4) << 12 << '\n';
cout << left << setw(4) << 213 << left << setw(4) << 8 << '\n';

輸出

3   12  
213 8

填入特定字元

記得要有標頭檔 <iomanip>

int x = 3;
cout << setw(3) << setfill('0') << x << '\n'; // 003

endl 與 '\n' 的差別

endl 除了暫存之外,還會 flush 掉 output buffer
'\n' 只會單純換行,因此會比較快

cout << "hello, world" << endl;
cout << "It's MyGo!!!!! " << 123 << '\n';

IO 優化

競程選手們習慣在主程式第一行就寫上

ios::sync_with_stdio(false);
cin.tie(0);

這樣速度會快很多
有時候原本 TLE 的題目就會因此 AC

sync_with_stdio()

先說 sync_with_stdio() 這個函數是什麼意思

這個函數是說「同步 C 與 C++ 的輸入/輸出流」。原本 C++ 的 cincout 是很快的,但是為了在混著使用時與 scanfprintf 同步,因此讓 C++ 的慢一點。原本 sync_with_stdio() 默認的數值是 true,所以我們上述那一行 sync_with_stdio(false) 就會把它關掉

cin.tie()

在原本 C++ 的 cin 中,都會自動呼叫 cout.flush() 函數,這會導致 output buffer 每次出入都刷新一次,非常沒效率,因此需要 cin.tie(0) 把它關掉

避免 scanf/printf 與 cin/cout 混用

如果加了上面那兩行,可想而知,原本為了協調 C 與 C++ 的輸入輸出就會被破壞。一旦混用了就會出現不可預期的後果 (順序會亂掉),這部分請讀者自行體會幾次就會知道了

參考資料


ShanC 程式競賽筆記
作者: ShanC
更新: 2024/1/10