문제 상황
C++에서 형식화된 추출 연산자(>>)를 사용한 후 std::getline()을 호출하면 입력이 건너뛰어지는 현상이 발생할 수 있습니다. 다음 코드를 통해 이 문제를 간단히 확인해 보겠습니다.
예제 코드
#include <iostream>
#include <string>
using namespace std;
int main(){
string name;
string city;
if (cin >> name && getline(cin, city)){
cout << "Your name " << name << " and city " << city;
}
}출력 결과
Amal Your name Amal and city
실행 결과를 보면 프로그램이 두 번째 입력(도시 이름)을 받지 못하는 것을 알 수 있습니다. 경우에 따라 두 번째 입력을 받기는 하지만, 출력 결과에는 첫 번째 입력만 표시되기도 합니다. 그렇다면 왜 이런 동작이 발생하는 걸까요?
원인 분석
이 문제의 핵심 원인은 첫 번째 문자열을 입력한 후 Enter(또는 Return) 키를 누른다는 점에 있습니다. Enter 키를 누르면 현재 입력 줄 뒤에 개행 문자인 '\n'이 삽입되는데, 바로 이 문자가 문제를 일으킵니다.
입력 스트림의 동작을 자세히 살펴보면 다음과 같습니다.
cin >> name은 공백이나 개행 문자 앞까지만 읽고, 구분자 역할을 한 개행 문자는 입력 버퍼에 그대로 남겨둡니다.- 이후 호출된
getline(cin, city)는 버퍼에서 개행 문자를 찾는 순간 입력을 종료하기 때문에, 버퍼에 이미 남아 있던'\n'을 즉시 만나 아무것도 읽지 않고 빈 문자열을 반환하게 됩니다.
즉, 이름으로 "Amal"을 입력했다면 내부적으로 입력 버퍼에는 "Amal\n"이 존재하고, >> 연산자가 "Amal"만 가져간 뒤 남은 '\n' 때문에 getline()이 조기에 종료되는 것입니다.
해결 방법: std::cin.ignore() 활용
이 문제를 해결하는 가장 간단한 방법은 첫 번째 추출 연산 직후 std::cin.ignore()를 호출하는 것입니다. 이 함수는 버퍼에서 다음으로 사용 가능한 문자(여기서는 개행 문자) 하나를 버려 주므로, 이후 getline()이 정상적으로 사용자 입력을 받을 수 있게 됩니다.
수정된 코드
#include <iostream>
#include <string>
using namespace std;
int main(){
string name;
string city;
if (cin >> name){
cin.ignore(); // 버퍼에 남아 있는 '\n' 문자 제거
if (getline(cin, city)){
cout << "Your name " << name << " and city " << city;
}
}
}이렇게 수정하면 첫 번째 입력 후 남은 개행 문자가 제거되어, 두 번째 입력인 도시 이름까지 정상적으로 처리됩니다. 참고로 여러 줄의 혼합 입력을 다룰 때는 cin.ignore(numeric_limits<streamsize>::max(), '\n')처럼 최대치를 지정하여 버퍼 전체를 비우는 방법도 널리 사용됩니다.