getline과 cin

같이 있을 때 골치아픈 두 놈, 차이점을 알아보자
Posted on 2023-08-25 by GKSRUDTN99
Problem Solving CPP

PS를 하다 보면 공백 단위가 아닌,

이 문제처럼 한 줄 단위로 입력을 받아야 하는 경우가 간혹 있습니다.

이 때, C++ 스타일로 입출력을 받을 수 있는 함수가 바로 getline()입니다.


getline()

getline 함수는 <string> 헤더에 포함된 함수로,

원형 먼저 살펴보도록 하겠습니다.

istream& getline (istream& is, string& str, char delim);
  1. istream& is: 입력을 받을 입력 스트림을 지정합니다.

    a. 보통 표준입출력(STDIO)를 통해 입력을 받으므로, cin을 넣어줍니다.

    b. 파일 입력 등을 사용하는 경우 파일 입력 스트림을 넣을 수도 있겠네요.

  2. string& str: 입력된 내용을 저장할 문자열 객체를 지정합니다.

  3. char delim: 입력을 끝낼 문자를 지정합니다. 입력하지 않는 경우, '\n'가 기본값으로 사용됩니다.


위에서 예시로 든 문제처럼, ,를 기준으로 입력을 받고 싶다면

string s;
getline(cin, s, ',');

이렇게 사용할 수 있습니다.



주의점

이렇게 편한 getline도 유의할 점이 있습니다.

바로, 우리가 주로 사용하는 cin과 함께 사용하게 될 경우 입니다.


cingetline은 입력을 끝내는 기준에서도 차이가 있지만,

입력 버퍼에 남아있는 문자들을 처리하는 방식에도 차이가 있습니다.


cin의 경우에는, delimiter로 사용되는 ' '(공백)과 '\n'(개행문자)가 입력 버퍼에 남아있으면,

delimiter가 나오지 않을 때 까지 입력 버퍼 앞쪽의 내용을 버립니다. (Trim 처리)

delimiter가 아닌 다른 문자를 입력 받고, 다시 delimiter를 만나면,

해당 delimiter는 입력 버퍼에 둔 채, 입력을 종료합니다.



getline의 경우에는, cin처럼 앞쪽 delimiter를 처리하는 Trim 과정이 없어,

입력 버퍼에 delimiter가 남아있다면 그대로 입력을 끝내버립니다.

또한, cin과는 달리,

getline은 delimiter를 만나게 되면, 해당 delimiter를 입력 버퍼에서 제거합니다.



예시1

string a;
int b;
getline(cin, a);
cin >> b;

// 입력:
// Hello World!
// 3
//
// 결과:
// a: Hello World!
// b: 3

위 경우, a와 b에 어떤 입력이 들어와 있을지 생각해보면,

처음에는 입력 버퍼에는 'Hello World!\n3'가 들어있습니다.

getline은 'Hello World!'를 a에 저장하고, delimiter인 '\n'을 버퍼에서 제거하여,

입력 버퍼에는 '3'만 남아있게 됩니다.

cin은 입력 버퍼에 남은 3을 입력받아, b에 3을 저장하고, 입력을 종료합니다.

따라서, a에는 'Hello World!', b에는 '3'이 정상적으로 입력됩니다.


예시2

int a;
string b;
cin >> a;
getline(cin, b);

// 입력:
// 3
// Hello World!
//
// 결과:
// a: 3
// b: ""

반대로, 이 경우에는 a와 b에 어떤 입력이 들어오는지 살펴보겠습니다.

처음 입력 버퍼에는 '3\nHello World!'가 들어있습니다.

cin은 입력 버퍼에 있는 3을 a에 저장하고, delimiter인 '\n'을 버퍼에 남겨둡니다.

따라서, 이제 입력 버퍼에는 '\nHello World!'가 들어있습니다.

getline은 입력 버퍼 제일 앞쪽에서 delimiter인 '\n'을 입력 받았으니,

'\n'을 입력버퍼에서 제거하고, b에는 아무것도 저장하지 않은 채, 입력을 종료합니다.

따라서, a에는 3이 정상적으로 입력되지만, b에는 빈 문자열만 입력되는, 원하지 않는 상황이 생길 수 있습니다.


해결방법

많은 해결 방법이 있겠지만, 여기서는 입력 버퍼의 제일 앞에 있는 문자들을 없애는

cin.ignore() 함수를 활용한 방식을 사용하겠습니다.

int a;
string b;
cin >> a;
cin.ignore();
getline(cin, b);

// 입력:
// 3
// Hello World!
//
// 결과:
// a: 3
// b: Hello World!

이전과 동일하게 a를 입력받고 난 뒤에, 입력 버퍼에는 '\nHello World!'가 저장되어 있을겁니다.

하지만, cin.ignore()가 호출되면 입력 버퍼 제일 앞의 '\n'를 제거해

입력 버퍼에는 'Hello World!'만 남게 되고,

이번에는 getline 함수가 정상적으로 입력을 받아 b에 'Hello World!'가 저장되게 됩니다.


cin.ignore 함수를 잘 사용하면, 입력 버퍼에서 여러 문자를 제거하거나,

특정 문자가 나올 때까지 입력 버퍼를 제거할 수 있으니, 공식 문서에서 한번 훑어보는 걸 추천드립니다.



정리

cin은 앞쪽 delimiter들을 무시하지만, 입력 버퍼에 delimiter를 남겨둔다.

getline은 앞쪽 delimiter를 무시하지 못하지만, 입력 버퍼에 delimiter를 남기지 않는다.

cin.ignore()은 입력 버퍼 앞의 문자들을 지운다.

...
Anonymous    May 2, 2024, 3:27 p.m.

좋은 글 잘 보고 갑니다

Updated: May 2, 2024, 4:52 p.m.