0%

0-6 進階輸入輸出

輸入含空白的字串

若輸入一個字串,使用 cin 會讀入到空白為止,但是,如果輸入是像這樣:

1
dasd sakf jfsak fsakl

那該怎麼讀入呢?

可以使用 4 次 cin,但如果空白個數不定,就糟糕了。

在這裡,介紹新的輸入字串方式:

1
2
string s;
getline(cin,s);

getline(cin,字串名) 可以讓你輸入整行的含空白字串,直到讀入換行符號’\n’為止。

於是可以這樣輸入:

1
2
3
string s;
getline(cin,s);
cout<<s<<'\n';

getline其實也可以指定讀到特定字元為止,附上詳細教學連結

注意,若使用char[]宣告字串,語法不同,需這樣寫:

1
2
3
char s[105];
cin.getline(s);
cout<<s<<'\n';

這份講義之後的code,會全數使用string。

getline 與 cin 混用時

輸入一個整數,然後輸入一個含空白的字串,要怎麼寫呢?

直覺的想法可能是:

1
2
3
4
5
6
int n;
string s;
cin >> n;
getline(cin, s);
cout << n << '\n';
cout << s << '\n';

然而,輸入若是:

1
2
3
dasd fasf gasf

輸出的結果卻是:

1
2
3

為什麼會這樣呢?

還記得 cin 一個整數時的運作原理嗎?一直讀入直到遇見不是整數的字元。

那 getline 的運作原理是,讀入直到遇見換行字元。

發現了嗎?若輸入的檔案是一整數、換行、一字串,cin 遇到換行停在換行的位置,這時使用 getline,就不幸的吃到那個換行後結束了。因此讀到的字串什麼都沒有。

要怎麼解決這個問題呢?最簡單的方法是再呼叫一次getline:

1
2
3
4
5
6
7
int n;
string s;
cin >> n;
getline(cin, s);
getline(cin, s);
cout << n << '\n';
cout << s << '\n';

然而,這麼寫會影響程式可讀性。因此,可以用 cin.ignore() 來表示我要忽略下一個字元:

1
2
3
4
5
6
7
int n;
string s;
cin >> n;
cin.ignore();
getline(cin, s);
cout << n << '\n';
cout << s << '\n';

這樣一來,換行字元就成功被跳過了!

cin/cout 加速

cin/cout 其實是一個速度很慢的功能,原因請點連結

而速度於程式解題競賽中是相當重要的一部分,因此,我們要想辦法讓 cin/cout 加速。

加速的方法有以下兩種:

  1. 使用輸入優化

    也就是在上方連結可看到的:

    1
    ios::sync_with_stdio(0), cin.tie(0);

    在main函式的開頭,打上這句,cin就加速許多,原因一樣在上方那篇。

    因此看起來會像這樣:

    1
    2
    3
    4
    5
    #include<bits/stdc++.h>
    using namespace std;
    int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    }
  2. 避免使用 endl

    endl其實是由,’\n’與flush組成,flush會使目前輸出的所有東西立刻顯現至螢幕上,但作為代價,其速度並不高。因此,細心的讀者可以注意到,本講義中,所有需要換行的場合,都是使用’\n’進行換行

以上兩點,需同時使用,才能快速進行高達百萬級的輸入輸出。

若只使用第一點,不使用第二點,則在輸出時仍然會因為flush過慢拖累整體執行效率。

若只使用第二點,雖然輸出時不會 flush,但 cin 時預設也會 flush,因此依然很慢。

雖然目前可能還不需要用到,但是在TLE時,請務必想想:是不是輸入太慢造成的問題?

練習

TOJ 5

TOJ 355

355這題會用到一點迴圈的概念,可以先往後讀,之後再回來。

AC Code

1
2
3
4
5
6
7
8
9
// TOJ 5
#include<iostream>
using namespace std;

int main() {
string s;
getline(cin, s);
cout << "Hello ," << s << " !\n";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// TOJ 355
#include<bits/stdc++.h>
using namespace std;

int n, k;

int main(){
ios::sync_with_stdio(0), cin.tie(0); // 試試看把這行刪掉會發生什麼事
cin >> n >> k; // k 無用
int mx = 0, sec = 0; // 紀錄當前第一大與第二大數
for(int i=0,x;i<n;i++){
cin >> x;
if(x > mx){ // 比第一大還大
sec = mx;
mx = x;
}
else if(x > sec){ // 不比第一大還大,但比第二大還大
sec = x;
}
}
cout << sec << '\n';
}