<aside> 😮 I/O는 예술이다. C++로부터, C, 그리고 심지어 시스템 호출까지 내려가 보자. 점점 아래로 내려갈수록 속도는 빨라지고 우리가 느끼는 기쁨은 2배가 된다(속도가 2배씩 빨라지기 때문이다). 이 기쁨을 함께 누리고자 글을 쓰게 되었으니, 바로 출발해 보자.
</aside>
문제가 중요한 것은 아니므로 빠르게 훑고 넘어가 보자. 주어진 문자열의 단어의 개수를 세는 문제이다. 단어의 공백은 ‘ ‘, 즉 스페이스로 구분된다. 여기에서 함정은 단어가 공백으로 시작하거나 끝날 수 있는데, 공백이 연속해서 나오지 않는다고 한다. 한 마디로 "hello "
과 같은 경우나 "hello"
경우가 존재한다는 건데, 단어 하나하나 말고 주어진 문자열 전체의 앞뒤로 튀어나온 스페이스들만 주의하면 될 것이다.
문제 소개는 이정도만 하고 바로 출발해 보자.
#include <iostream>
using namespace std;
int main()
{
int wc = 0;
string dummy;
for (; cin >> dummy; ++wc) { }
cout << wc;
}
군더더기가 하나 없다. 아마 c++에서 이 문제를 표현할 수 있는 가장 깔끔한 방법인 것 같다. 바로 cin의 operator>>
가 자동으로 스페이스를 손질해 준다는 점을 이용한 건데, 이 때문에 문제의 추가 조건에 대해서 신경쓸 일이 없다. for 대신 while 을 사용하는 방법도 있겠다.
사실 우아해 보이려고 생략했는데, 이 코드대로 실행하면 40ms가 나오고, 12ms가 나오려면 ios::sync_with_stdio(false)
, cin.tie(nullptr)
을 적용해 주어야 한다. 혹시 이 둘을 처음 보는 사람이 있다면 cin.tie(nullptr)? 그거 왜 하는건데? (백준 문제풀이)를 한번 읽어보자.
(wc는 word count의 줄임말이고, 리눅스의 명령어이기도 한 만큼 줄여 썼다.)
High-level에서 low-level로 한 계단만 내려가 보자. 우아한 operator>>
를 이용하는 것은 좋지만, 위 코드가 비효율적이라는 것을 눈치챘는가? 바로 우리가 사용할 일이 전혀 없는 string dummy
에 계속해서 string
을 저장하고 있었다는 점이다. 저장하는 대신에 무시하는 방법이 있다.
#include <iostream>
constexpr auto STR_MAX = 0x7fffffffffffffff;
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int wc = 0;
for (; (cin >> ws).ignore(STR_MAX, ' '); ++wc) { }
cout << wc;
}
혹시 이 방법에 대해 별로 궁금하지 않거나 무슨 말인지 이해가 안된다면 아래 굵은 글씨로 된 문단까지 뛰어넘어도 무관하다. 별로 중요한 내용이 아니다.
위에서 2번째 줄의 STR_MAX는 i/o stream 객체의 최대 길이(stream max)인데, <iostream>헤더의 그 stream이냐고 묻는다면 맞다. 바로 stream이 지닐 수 있는 최대 길이를 뜻한다.