[C / C++] 문자열
문자열(string)이란 일련의 연속된 문자(character)들의 집합이다.
C++에서는 이러한 문자열을 C언어 스타일의 문자열, string 클래스를 이용한 문자열 이렇게 두 가지 방법으로 생성할 수 있다.
--------------------------------------------------------------------------------------------------------------------------------
1. 널(NULL) 문자
C++에서 문자열 변수는 문자열의 끝을 프로그램에 따로 알려주어야 한다.
그래야만 프로그램이 실제 문자열에 속한 값과 그 외에 쓰레깃값으로 구분할 수 있다.
따라서 문자열이 끝나면, 문자열의 끝을 의미하는 문자를 하나 더 삽입해 준다.
이러한 문자를 널(NULL) 문자라고 하며, \0으로 표시하고 아스키코드값은 0이다.
널 문자의 유무로 문자형 데이터 배열과 문자열을 서로 구분할 수 있다.
--------------------------------------------------------------------------------------------------------------------------------
2. C언어 스타일 문자열
문자형 자료형인 char을 배열 형식으로 여러 개 묶으면 그게 곧 문자열 변수가 된다.
int main()
{
const int SIZE = 20; // 실제 입력은 19자 (\0이 한 칸 차지)
char name[SIZE];
char gender[SIZE];
cout << "이름을 입력하세요! : ";
cin >> name;
cout << "성별을 입력하세요! : ";
cin >> gender;
cout << "이름 : " << name << " | 성별 : " << gender << endl;
return 0;
}
/*실행 결과
이름을 입력하세요! : 홍길동
성별을 입력하세요! : 남자
이름 : 홍길동 | 성별 : 남자
*/
C++에서 문자형 배열로 문자열을 입력받기 위해서는 문자열이 저장될 문자형 배열을 미리 생성해놔야 한다.
하지만 여기에는 다음과 같은 두 가지 문제가 있는데,
1. 문자열에 띄어쓰기가 들어가면 안 된다.
2. 20byte 이상의 문자열을 입력하면 프로그램이 강제 종료된다.
C++에서 cin 객체는 띄어쓰기를 포함한 탭 문자, 캐리지 리턴 문자 등을 모두 문자열의 끝으로 인식한다.
따라서 띄어쓰기를 포함한 문자열을 전부 입력받고, 데이터 크기에 상관없이 입력받으려면 cin 객체의 get() 메소드와 ignore() 메소드를 사용해야 한다.
int main()
{
const int SIZE = 20;
char name[SIZE];
char gender[SIZE];
cout << "이름을 입력하세요! : ";
cin.get(name, SIZE).ignore(SIZE, '\n');
cout << "성별을 입력하세요! : ";
cin.get(gender, SIZE).ignore(SIZE, '\n');
cout << "이름 : " << name << " | 성별 : " << gender << endl;
return 0;
}
/*실행 결과
이름을 입력하세요! : abcd efgh ijkl mnop qrst uvwx
성별을 입력하세요! : qweasddfgcvb qw eeqqqaz
이름 : abcd efgh ijkl mnop | 성별 : qweasddfgcvb qw ee
*/
위의 예제는 get() 메소드를 사용하여 띄어쓰기를 포함한 이름이나 성별을 입력할 수 있다.
또한, ignore() 메소드를 사용하여 20byte 이상의 이름이나 성별을 입력해도 정확히 SIZE에 맞는 byte 까지만 입력받고 있다.
C언어 스타일의 문자열 입력에서는 입력할 문자형 배열의 길이를 알고 있어야만 한다는 단점이 있다.
--------------------------------------------------------------------------------------------------------------------------------
3. string 클래스
string 라이브러리를 통해 string 클래스를 이용하면 C언어 스타일의 문자형 배열을 통해 사용하는 문제점들을 쉽게 극복할 수 있다.
string 클래스를 사용하기 위해서는 우선 string 헤더 파일을 포함시켜야 하며, std 네임스페이스가 필요하다.
string 클래스를 사용할 경우 문자열을 일반 타입처럼 사용할 수 있게 해 주어 일반 변수처럼 사용이 가능하다.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 = "Hello World!";
string str2;
str2 = str1;
cout << str2 << endl;
cout << str2[0] << ", " << str2[1] << str2[2] << endl;
return 0;
}
/*실행 결과
Hello World!
H, el
*/
일반 변수처럼 선언과 동시에 초기화가 가능하며, 변수끼리의 대입도 가능하다.
[]을 이용해 문자형 배열처럼 한 문자씩 접근도 가능하고, 마지막에 NULL문자가 포함되어 있다.
string str1 = "Hello ";
string str2 = "World!";
string str3 = str1 + str2;
cout << str3 << endl;
/*실행 결과
Hello World!
*/
문자열끼리의 + 연산과 += 연산도 가능하다.
int main()
{
string name, gender;
cout << "이름을 입력하세요! : ";
getline(cin, name);
cout << "성별을 입력하세요! : ";
getline(cin, gender);
cout << "이름은 : " << name << " | 성별은 : " << gender << endl;
return 0;
}
/*실행 결과
이름을 입력하세요! : 홍길 동
성별을 입력하세요! : 남 자
이름은 : 홍길 동 | 성별은 : 남 자
*/
cin 객체의 공백을 문자열의 끝으로 인식하는 문제는 문자열을 한 행씩 읽을 수 있는 getline() 함수를 통해 입력받으면 된다.
--------------------------------------------------------------------------------------------------------------------------------
4. string 메소드
string 메소드는 string 클래스에 정의된 문자열과 관련된 작업을 할 때 사용한다.
1) length(), size()
string str = "Hello";
cout << str.length() << endl; // 5
cout << str.size() << endl; // 5
length와 size 모두 같은 같을 반환 하지만 다른 의미를 가진다.
length의 경우 문자열의 길이를 반환하고 size의 경우 객체가 메모리에서 사용하는 크기를 반환한다.
또한, length의 경우 널 문자까지의 길이가 아닌 실제 문자열의 길이만 반환한다.
2) append()
문자열의 끝에 새로운 문자열을 추가하는 메소드이다. 사용방법은 다음과 같다.
1) 문자열.append("새로운 문자열");
2) 문자열.append("새로운 문자열", 시작번호, 개수);
string str1 = "Hello";
string str2 = str1;
cout << str1.append(" World!") << endl;
cout << str2.append(" World!", 1, 3) << endl;
// Hello World!
// HelloWor
문자열의 끝에 추가하려는 문자열이 추가되며, 두 번째의 경우 추가하려는 문자열의 1번 인덱스부터 3개의 문자가 입력된다.
3) find()
find()는 원하는 문자열의 시작 위치를 반환하는 메소드이다. 사용방법은 다음과 같다.
1) 문자열.find(찾을 문자열);
2) 문자열.find(찾을 문자);
3) 문자열.find(찾을 문자열, 시작 위치);
find()는 해당 문자열에서 찾을 문자열을 찾지 못하면, string::size_type의 string::npos라는 상수를 반환한다.
string str1 = "Hello";
cout << str1.find("lo") << endl;
cout << str1.find("l") << endl;
cout << str1.find('o', 3) << endl;
if (str1.find('k') == string::npos)
cout << "해당 문자열을 찾지 못했습니다!" << endl;
else
cout << "해당 문자열을 찾았습니다!" << endl;
// 3
// 2
// 4
// 해당 문자열을 찾지 못했습니다.
2번째의 경우를 보면 l이 2개가 존재하는데, 처음 만난 l의 위치를 반환한다. 즉 같은 문자열이 여러 개 있으면 그중 제일 앞에 인덱스를 반환한다.
3번째 경우는 시작 위치 인덱스부터 검색하여 해당 문자열을 찾게 된다.
4) compare()
compare() 메소드는 두 문자열 간의 내용을 비교하는 메소드이다. 사용방법은 다음과 같다.
기준 문자열.compare(비교할 문자열)
만약 두 문자열이 일치한다면 0을 반환한다.
기준 문자열이 비교할 문자열보다 사전 편찬 순으로 앞일 경우 기준. compare(비교) < 0, 뒤일 경우 기준 compare(비교) > 0 이 된다.
string str1 = "Ha";
string str2 = "Hb";
if (str1.compare(str2) == 0)
cout << "두 문자열 일치" << endl;
else if (str1.compare(str2) < 0)
cout << str1 << "가 사전편찬 순서 앞" << endl;
else
cout << str2 << "가 사전편찬 순서 앞" << endl;
// Ha가 사전편찬 순서 앞
5) replace()
replace() 메소드는 특정 문자열을 다른 문자열로 대체하는 메소드이다. 사용방법은 다음과 같다.
문자열.replace(변경할 문자열 시작 위치, 새로운 문자열 길이, 새로운 문자열);
string str1 = "Hello World!";
string a = "World!";
string b = "Programming!";
int index = 0;
index = str1.find(a);
cout << str1.replace(index, a.length(), b) << endl;
// Hello Programming!
변경할 문자열의 시작 위치를 find() 메소드를 통해 찾는 것이 좋다.
6) capacity(), max_size()
capacity() 메소드는 해당 문자열이 재할당받지 않고 저장할 수 있는 최대 문자열의 길이를 반환한다.
max_size() 메소드는 해당 문자열이 최대한 할당받으면 가질 수 있는 최대 문자열의 길이를 반환한다.
string str = "Hello World!";
cout << str.length() << endl;
cout << str.capacity() << endl;
cout << str.max_size() << endl;
// 12
// 15
// 9223372036854775807