본문 바로가기
서적 정리/C++ 기초 플러스

13.문자열(string)

by 민돌이2 2022. 7. 26.

문자열(stirng)이란 메모리에 바이트 단위로 연속적으로 저장되어 있는 문자들을 말한다. 문자들이 메모리에 바이트 단위로 연속적으로 저장된다는 것은, 문자열을 char형의 배열에 저장할 수 있다는 것을 의미한다. 즉, char형의 배열을 string이라고 받아들이면 된다. 이때 문자열을 구성하는 각 문자들은 배열의 원소에 하나씩 저장된다. 또한 문자열의 마지막 문자는 반드시 널 문자(null character)여야 하고, 널 문자는 \0로 쓴다. ASCII 코드가 0인 문자이다.

char cat[4] = {'f', 'a', 't', '\0'};

큰따옴표로 묶인 문자열은 널 문자를 암시적으로 가지고 있다. 따라서 아래와 같은 코드가 가능하다.

char fish[] = "Bubbles";

문자열을 저장할 char형 배열은, 그 크기가 널 문자까지 포함하여 그 문자열에 들어 있는 모든 문자들을 다 넣을 수 있을 만큼 충분히 커야 한다. 즉, 문자가 4개라면 원소의 개수를 5개 이상 잡아야 한다.

char dog[5] = "Bow!"

 

 

 

문자열 상수의 결합

어떤 문자열이 너무 길어서 한 행으로 표현할 수 없다. 이런 경우 C++에서는 문자열 상수들을 결합할 수 있다. 아래의 코드는 같은 문자열을 출력한다.

cout << "Hello World!" <<endl;
cout << "Hello " "World!" << endl;

 

 

 

배열에 문자열 사용

배열에 문자열을 넣는 가장 일반적인 방법은 두 가지이다.

  1. 배열을 문자열 상수로 초기화 한다.
  2. 키보드 입력이나 파일 입력을 배열에 저장한다.
int main()
{	
	using namespace std;
	
	const int size = 15;
	
	char name1[size] = "Minju";
	char name2[size];

	cout << "name1 : " << name1 << endl;
	cin >> name2;
	cout << "name2 : " << name2 << endl;

	return 0;
}

결과

 

 

문자열 입력

문자열 입력에는 한 가지 결함을 갖고 있다. 문자열의 끝을 널 문자로 받기 때문이 발생한다.

int main()
{	
	using namespace std;
	
	const int size = 10;
	
	char name1[size];
	char name2[size];

	cout << "name1 : ";
	cin >> name1;
	cout << "name2 : ";
	cin >> name2;

	cout << endl << "----------------" << endl;
	cout << "name1 : " << name1 << endl;
	cout << "name2 : " << name2 << endl << endl;

	return 0;
}

결과

결과를 보면 name1을 Min ju로 입력했을 때, name2의 입력을 받지 않고 넘어가는 것을 알 수 있다. 이렇게 되는 이유는 cin이 문자열의 끝을 인식하는 방법 때문이다. 키보드로는 널 문자를 입력할 수 없기 때문에, cin에게 문자열의 끝을 알려 주는 다른 수단이 필요한데, cin은 빈칸, 탭, 캐리지 리턴과 같은 화이트스페이스가 있으면 그 위치에서 문자열이 끝난 것으로 간주한다. 즉, char형의 배열에 저장하기 위해 키보드로부터 입력을 받을 때 cin은 하나의 단어만 읽어 배열에 저장하고 널 문자를 끝에 추가한다.

 

 

한 번에 한 행의 문자열 입력 읽기

문자열 입력에서 띄어쓰기는 널 값으로 받기 때문에 문제가 발생한다. 이런 경우 단어 단위의 문자열 입력이 아닌 행 단위의 문자열 입력이 필요하다. 행 단위로 문자열을 입력하는 클래스 멤버 함수는 istream파일의 cin 클래스에 두 가지가 존재한다.

  1. getline()
  2. get()

둘다 전체 입력 행을 읽는다. 즉, 개행 문자가 나올 때까지 읽는다. 하지만 getline()은 개행 문자를 읽어서 폐기하는 반면, get()은 입력 큐에 개행 문자를 남겨 둔다.

 

getline()을 이용한 행 단위 입력

getline() 함수는 Enter 키에 의해 전달되는 개행 문자를 입력의 끝으로 간주하여 한 행 전체를 읽는다.

int main()
{	
	using namespace std;
	
	const int size = 10;
	
	char name1[size];
	char name2[size];

	cout << "name1 : ";
	cin.getline(name1, size);
	cout << "name2 : ";
	cin.getline(name2, size);

	cout << endl << "----------------" << endl;
	cout << "name1 : " << name1 << endl;
	cout << "name2 : " << name2 << endl << endl;
	
	return 0;
}

결과

결과를 보면 띄어쓰기로 분리되어 있어도 온전하게 읽는 것을 알 수 있다. 

 

get()을 이용한 행 단위 입력

get() 함수도 getline() 함수와 같다. 하지만 큰 차이점이 하나 존재하는데, 개행 문자를 읽어서 버리지 않고 입력 큐에 그대로 남겨둔다는 점이다.

cin.get(name1, size); //문제 없음
cin.get(name2, size); //문제 발생

위의 코드는 문제가 발생한다. 첫 번째 행이 입력 큐에 개행 문자를 그대로 남겨 두기 때문에, 두 번째 행은 첫 번째 행의 개행 문자를 첫 문자로 만나게 된다. 첫 번째 문자는 널 값이다. 즉, nam2의 입력값을 받지 않고 넘어갈 것이다. 이는 아래의 방법으로 해결할 수 있다.

cin.get(name1, size);
cin.get();
cin.get(name2, size);

다음 방법은 두 개의 클래스 멤버 함수를 결합하여 사용하는 것이다.

cin.get(name1, size).get();
cin.get(name2, size);

get() 함수의 리턴값이 본인의 참조임을 알면 왜 이런 구문이 가능한지 이해할 수 있다. 이 방법은 getline() 함수 역시 사용할 수 있다.

 

빈 행과 기타 문제점

get() 함수의 경우 빈 행을 읽으면 failbit라는 것이 설정된다. failbit은 계속되는 입력을 막고, 입력을 복원하려면 아래의 명령을 사용해야 한다.

cin.clear();

입력 문자열이 대입된 공간보다 더 큰 경우가 생길 수 있다. 즉, 5개의 원소를 갖는 char형 배열이 10개의 입력이 들어왔을 경우 문제가 생긴다는 것이다. 이때, getline()과 get()은 나머지 문자들을 입력 큐에 그대로 남겨 둔다. 그러간 부가적으로 getline()은 failbit을 설정하고 더 이상의 입력을 받지 않는다.

 

 

문자열과 수치의 혼합 입력

행 단위의 문자열 입력과 수치 입력을 혼합하여 사용하면 문제가 발생할 수 있다.

int main()
{	
	using namespace std;
	
	const int size = 10;
	char name[size];
	int year;

	cout << "출생 년도 : ";
	cin >> year;
	cout << "이름 : ";
	cin.getline(name, size);

	cout << "-----------" << endl;
	cout << "출생 년도 : " << year << endl;
	cout << "이름 : " << name << endl;

	return 0;
}

결과

출생년도의 정수값을 입력받고, 이름의 문자열을 입력할 기회를 주지 않는다. cin이 출생년도를 읽고, Enter 키가 만들어 내는 개행 문자를 입력 큐에 남겨 두기 때문에 발생하는 문제이다. 정리하자면, 출생년도를 받아낸 cin에서 Enter 키로 인해 남겨진 개행 문자가 getline() 함수를 만나 종료시키는 것이다.

이 문제를 해결하는 방법은 getline()을 만나기 전 개행 문자를 읽는 것이다.

cin >> year;
cin.get();

cin >> 를 보면 리턴값이 std::iostream이다. 즉, get() 함수를 불러 올 수 있다.

(cin >> year).get();
728x90

'서적 정리 > C++ 기초 플러스' 카테고리의 다른 글

17.열거체(enumeration)  (0) 2022.08.03
16.공용체(union)  (0) 2022.08.03
15.구조체(struct)  (0) 2022.08.03
14.string 클래스  (0) 2022.07.29
12.배열(array)  (0) 2022.07.26
11.C++ 산술 연산자  (0) 2022.07.26
10.부동 소수점수(floating point)  (0) 2022.07.25
9.const 제한자  (0) 2022.07.25

댓글