[C++] getline 함수 사용법

getline 함수

getline 함수는 입력 스트림( input stream )으로부터 구분자( delimiter )까지의 문자열을 입력받는 함수입니다.

만약, 구분자를 지정하지 않은 경우 개행 문자( '\n' )가 기본 구분자가 됩니다.

 

이 함수를 사용하려면 다음의 헤더를 포함해야 합니다.

#include <string>

 

함수의 정의는 다음과 같습니다.

istream& getline( istream& is, string& str);
istream& getline( istream& is, string& str, char deli );

// C++ 11 이후
istream& getline( istream&& is, string& str);
istream& getline( istream&& is, string& str, char deli );

 

이 정의에서, 매개 변수 is는 아래 이미지의 C++ 입력스트림 istream을 가리킵니다.

getline 함수는 이 istream 클래스를 상속받은 사용자 입력( cin ), 파일( file ), std::string 객체로부터 데이터를 입력받을 수 있습니다.

 

C++의 표준 입출력 상속 관계 ( 출처: cplusplus.com )

 

마지막 매개 변수인 deli는 입력 문자열을 분할하는 구분자입니다.

이 함수는 입력 스트림의 현 위치부터, 이 구분자까지의 문자열을 구하여, str에 그 값을 전달합니다.

 

아래 예문은 getline의 기본적인 사용법입니다.

#include <iostream>
#include <string>
using namespace std;

int main(){

  string str1, str2, str3;
  getline( cin, str1, ',');
  getline( cin, str2, ',');
  getline( cin, str3);

  cout << str1 << " , " << str2 << " , " << str3;
}

▲입력

apple,banana,strawberry

▼출력

apple , banana , strawberry

위의 마지막 getlne 함수는 구분자를 지정하지 않은 버전이므로, 개행 문자가 구분자가 됩니다.

따라서, 사용자가 enter를 입력하면, 입력이 끝나고 결과가 출력됩니다.

 

 

다음 예문은 std::cin 객체의 >> 연산자와 getline 함수를 같이 사용하는 예문입니다.

int main ()
{
  string name1, name2, name3;

  cout << "Please, enter names: \n";

  cin >> name1;

  getline (cin, name2);
  getline (cin, name3);
  
  cout << name1 << "|,|" << name2 << "|,|" << name3;

  return 0;
}

▼출력

Please, enter names: 
1
2
output: 1|,||,|2

그런데, 위에서도 첫 번째 예문처럼, 세 번의 입력을 기대했는데, 1과 2를 입력하자, 바로 결과가 출력되었습니다.

왜 이런 걸까요?

 

이것은, cin 객체의 >> 연산자가 공백, 탭, 개행 문자의 전까지만 입력을 받고 리턴하기 때문입니다.

문자 '1' 뒤에 개행 문자가 있기 때문에, name1에는 '1'이 입력되고, 입력 스트림에는 아직 개행 문자가 남아 있습니다.

이 개행 문자는 getline 함수를 통해서 두 번째 입력을 받을 때, 구분자로 역할을 하므로, name2는 아무런 문자도 입력받지 못했습니다.

그리고, 세 번째 입력 시, name3에 '2'가 입력되어서 위의 결과가 나오게 된 것입니다.

 

이 결과를 수정하려면, 첫 번째 입력 시, 입력 스트림에 아직 남아있는 개행 문자를 제거하면 될 것입니다.

이때 사용하는 함수가 istream::ignore입니다.

( cin 클래스는 istream의 파생 클래스입니다. 위의 이미지 참조. )

istream& ignore( streamsize n = 1, int delim = EOF );

여기서는, 개행 문자만 제거하면 되므로, 다음 문장으로 문제는 해결됩니다.

cin.ignore();

▼출력

Please, enter names: 
1
2
3
output: 1|,|2|,|3

 

참고로, istream 스트림에 남아있는 모든 문자를 무시하려면, 아래와 같이 하면 됩니다.

#include <limits>

cin.ignore( std::numeric_limits<std::streamsize>::max() );

이때, max()의 값을 인자로 함수에 입력하면, ignore는 매우 큰 숫자를 말하는 것이 아니라, 제한이 없다는 뜻으로 받아들입니다.

따라서, 스트림에 남아 있는 모든 문자를 무시(제거)하게 됩니다.

 

 

  다음 예문은, 콤마로 구분된 문자열로부터, 숫자의 합을 구하는 예문입니다.

#include <iostream>
#include <string>
#include <sstream>  // for istringstream
using namespace std;

int main(){

    string str = "10, 2, 3, 5, 7, 23";

    istringstream input(str);   // std::string으로부터 입력 스트림 생성
    string val;

    int sum = 0;
    while( getline( input, val, ',')){	// ??
    
        sum += stoi(val);	// string을 숫자로 변환
    }

    cout << "sum: " << sum;
}

▼출력

sum: 50

 

위에서 getline 함수가 반환하는 것은 istream 객체입니다.

그런데, 어떻게 위와 같이 while 구문을 사용할 수 있는 걸까요?

 

이것은 컴파일러에 의해서 암시적인 타입 변경이 일어나기 때문입니다.

while 구문은 괄호 안의 bool 값을 평가하는데, 이 값을 얻기 위해서 bool istream::operator () 함수를 호출하게 됩니다.

이 함수는 istream의 내부 상태 플러그에 따라, true와 false를 반환하는데, 스트림이 EOF( end of file )에 도달하거나 함수 호출을 하면서 오류가 발생하게 되면, 오류 상태가 되어 false를 반환하게 됩니다.

 

그래서, 위의 while 루프는 입력스트림의 끝에 도달하면, 루프를 벗어나게 되는 것입니다.

 

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유