6. 문자열(String)
1. 키워드
- 문자열(String)
string
클래스length()
와size()
메서드append()
메서드find()
메서드compare()
메서드replace()
메서드capacity()
와max_size()
메서드
2. C 스타일의 문자열
1) C++ 문자열
- 문자열이란 메모리에 저장된 일련의 연속된 문자(Character)들의 집합을 의미한다.
- C++에서는 이러한 문자열을 다음과 같은 두 가지 방법으로 생성할 수 있다.
1] C 스타일의 문자열
2] string
클래스를 이용한 문자열
2) C 스타일의 문자열
- C++에서는
""
(큰따옴표)를 사용해 표현되는 문자열을 문자열 상수(String Constant)라고 한다. - 상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않으며, 문자열의 내용 또한 변경할 수 없기 때문이다.
- C++에서
char
타입 배열을 선언하면 이 배열이 곧 문자 배열이 된다. - C++에서는 문자열의 길이에 제한을 두지 않는다.
3) 널(NULL
) 문자
- C++에서
char
타입 배열로 선언된 문자 배열은 문자열의 끝을 프로그램에 따로 알려주어야 한다. - 그래야만 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레깃값을 구분할 수 있다.
- 따라서 문자열에 속한 데이터가 끝나면, 문자열의 끝을 의미하는 문자를 하나 더 삽입해 준다.
- 이러한 문자를 널 문자라고 하며,
'\0'
으로 표시하고 아스키코드값은0
이다. - 널 문자의 유무로
char
타입 데이터 배열과 실제 문자열을 서로 구분할 수 있다. - 그러므로 문자열을 저장하기 위한
char
타입 배열을 선언할 때에는 반드시 널 문자까지 포함해서 생각해야 한다.
4) 문자열 입력
- C++에서 문자열을 입력 받기 위해서는 문자열이 저장될
char
타입 배열을 미리 생성해놔야 한다.
#include <iostream>
using namespace std;
int main() {
const int SIZE = 20;
char address[SIZE];
char name[SIZE];
cout << "자신의 이름을 적어주세요: ";
cin >> name;
cout << "자신이 살고 있는 도시를 적어주세요: ";
cin >> address;
cout << address << "에 살고 있는 " << name << "님~ 감사합니다!" << endl;
return 0;
}
// 자신의 이름을 적어주세요: 홍길동 (입력)
// 자신이 살고 있는 도시를 적어주세요: 서울 (입력)
// 서울에 살고 있는 홍길동님~ 감사합니다!
- 위의 코드는 사용자의 이름과 살고 있는 도시명을 입력 받는 것이다.
- 하지만 이 코드는 다음과 같은 두 가지 문제점을 안고 있다.
1] 이름에 띄어쓰기가 들어가면 도시명을 입력할 수 없다.
2] 20
바이트 이상의 이름이나 도시명을 입력하면 프로그램이 강제 종료된다.
- C++에서
cin
객체는 띄어쓰기를 포함한'\t'
(탭 문자),'\n'
(캐리지 리턴 문자) 등을 모두 문자열의 끝으로 인식한다. - 따라서 띄어쓰기를 포함한 문자열을 전부 입력받으려면
cin
객체의get()
메서드를 사용하여 다음처럼 수정해야 한다.
#include <iostream>
using namespace std;
int main() {
const int SIZE = 20;
char address[SIZE];
char name[SIZE];
cout << "자신의 이름을 적어주세요: ";
cin.get(name, SIZE).get();
cout << "자신이 살고 있는 도시를 적어주세요: ";
cin.get(address, SIZE).get();
cout << address << "에 살고 있는 " << name << "님~ 감사합니다!" << endl;
return 0;
}
// 자신의 이름을 적어주세요: 홍 길동 (입력)
// 자신이 살고 있는 도시를 적어주세요: 한국의 서울 (입력)
// 한국의 서울에 살고 있는 홍 길동님~ 감사합니다!
- 위의 코드는 띄어쓰기를 포함한 이름이나 도시명을 정확히 입력할 수 있게 되었다.
- 하지만 아직도
20
바이트 이상의 이름을 입력할 경우, 도시명을 입력 받지 못하는 문제점을 안고 있다. - 이 문제는
cin
객체의ignore()
메서드를 사용하여 다음처럼 수정할 수 있다.
#include <iostream>
using namespace std;
int main() {
const int SIZE = 20;
char address[SIZE];
char name[SIZE];
cout << "자신의 이름을 적어주세요: ";
cin.get(name, SIZE).ignore(SIZE, '\n');
cout << "자신이 살고 있는 도시를 적어주세요: ";
cin.get(address, SIZE).ignore(SIZE, '\n');
cout << address << "에 살고 있는 " << name << "님~ 감사합니다!" << endl;
return 0;
}
// 자신의 이름을 적어주세요: abcdefghijklmnopqrstuvwxyz (입력)
// 자신이 살고 있는 도시를 적어주세요: ABCDEFGHIJKLMNOPQRSTUVWXYZ (입력)
// ABCDEFGHIJKLMNOPQRS에 살고 있는 abcdefghijklmnopqrs님~ 감사합니다!
- 위의 코드의 실행결과를 살펴보면,
20
바이트 이상의 이름이나 도시명을 입력해도 정확히20
바이트까지만 입력 받고 있는 것을 확인할 수 있다.
- 위의 코드와 같이 C 스타일의 문자열 입력에서는 입력할 문자열의 길이를 미리 알고 있어야만 한다.
- 하지만 C++에서 제공하는
string
클래스를 이용하면 다음처럼 아주 간단하게 그 문제를 해결할 수 있다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string address, name;
cout << "자신의 이름을 적어주세요: ";
getline(cin, name);
cout << "자신이 살고 있는 도시를 적어주세요: ";
getline(cin, address);
cout << address << "에 살고 있는 " << name << "님~ 감사합니다!";
return 0;
}
// 자신의 이름을 적어주세요: 가나다라마바사아자차카타파하 (입력)
// 자신이 살고 있는 도시를 적어주세요: ABCDEFGHIJKLMNOPQRSTUVWXYZ (입력)
// ABCDEFGHIJKLMNOPQRSTUVWXYZ에 살고 있는 가나다라마바사아자차카타파하님~ 감사합니다!
- 위의 코드는 앞서 살펴본 문자열의 띄어쓰기 문제나 문자열의 길이와 상관없이 모든 문자열을 정확히 입력 받을 수 있다.
5) C 문자열 처리 함수
- C++에서 C 스타일의 문자열을 처리하기 위해 C 라이브러리의 문자열 처리 함수를 사용할 수 있다.
- 이러한 C의 문자열 라이브러리를 사용하기 위해서는 우선
cstring
헤더 파일을 포함해야 한다.
3. string
클래스
- C++은 문자열을 예전의 C 스타일뿐만 아니라, 새롭게 추가된
string
클래스를 이용하여 처리할 수 있도록 해준다. string
클래스는char
타입 배열보다 사용하기 편리하며, 문자열을 하나의 타입처럼 표현할 수 있게 해준다.- C++에서
string
클래스를 사용하기 위해서는 우선string
헤더 파일을 포함해야 한다. - 또한,
string
클래스는std
네임스페이스에 속해 있으므로,using
지시자를 사용하거나 해당 네임스페이스를 참조해야 한다.
1) 문자열 선언 및 초기화
- C++에서
string
객체를 사용한 문자열 선언 방식은 다음과 같다.
string str1; // 문자열의 선언
str1 = "C++ Programming"; // 문자열의 초기화
string str2 = "C++"; // 문자열의 선언과 동시에 초기화
string
객체는 위와 같의 문자열을 배열 형태가 아닌 단순한 변수로 선언한다.- 따라서 사용자가 길이를 명시하지 않아도 되며, 문자열 길이에 대한 문제는 C++ 프로그램이 자동으로 처리해 준다.
- 위의 코드에서 문자열
str1
은 선언 시 길이가0
인string
객체를 생성한다. - 그 후 문자열을 초기화하면 C++ 프로그램이 문자열
str1
의 길이를 자동으로 조절해 준다. - 따라서
string
객체를 사용하면char
타입 배열을 사용하는 것보다 훨씬 더 편리하고 안전하게 문자열을 처리할 수 있다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string dog;
cout << "현재 dog 변수의 길이는 " << dog.length() << "입니다." << endl;
dog = "Navi";
cout << dog << "! 정말 예쁜 이름이네요!" << endl;
cout << "현재 dog 변수의 길이는 " << dog.length() << "입니다." << endl;
cout << "강아지 이름의 첫 글자는 바로 " << dog[0] << "입니다." << endl;
return 0;
}
// 현재 dog 변수의 길이는 0입니다.
// Navi! 정말 예쁜 이름이네요!
// 현재 dog 변수의 길이는 4입니다.
// 강아지 이름의 첫 글자는 바로 N입니다.
- 위의 코드에서 보면
string
객체로 만든 문자열도 배열처럼 인덱스를 통해 다룰 수 있다는 것을 알 수 있다. - 또한, 길이가
0
인string
객체가 입력된 문자열에 따라 자동으로 길이가 조절됨을 알 수 있다.
한글
- 컴퓨터에서 한글은
2
바이트로 취급된다. - 따라서 위의 예제에서 한글을 입력하면 이름의 첫 글자로 이상한 문자가 출력될 것이다.
- 참고로
string
클래스의length()
나size()
메서드를 사용하면string
객체의 현재 길이를 알 수 있다.
2) 문자열 처리
- C++에서
string
객체를 이용한 문자열의 처리는char
타입 배열을 이용하는 방식보다 훨씬 더 간단하다. - C에서
char
타입 배열 사이의 대입 작업은strcpy()
나strncpy()
함수를 사용했다. - 하지만
string
객체를 이용한 문자열에서는=
(대입 연산자)만을 사용하여 간단히 대입 작업을 할 수 있다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "C++ is Cool!";
string str2;
str2 = str1; // 문자열 대입 연산
cout << str2 << endl;
return 0;
}
// C++ is Cool!
- 또한,
char
타입 배열 사이의 추가나 결합 작업은strcat()
이나strncat()
함수를 사용했다. - 하지만
string
객체를 이용하면+=
(복합 대입 연산자)나append()
메서드를 이용하여 손쉽게 추가나 결합을 할 수 있다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "C++ is ";
string str2 = "Cool! and funny!";
string str3;
str3 = str1 + str2; // 문자열 결합 연산
cout << str3 << endl;
str1 += str2; // 문자열 추가 연산
cout << str1 << endl;
return 0;
}
// C++ is Cool! and funny!
// C++ is Cool! and funny!
3) 문자열 입출력
string
객체를 이용한 문자열의 입력에는cin
객체를, 출력에는cout
객체를 사용할 수 있다.- 하지만
cin
객체를 이용한 문자열의 입력은 한 단어 단위로 수행된다. - 따라서 문자열을 한 행(Line)씩 읽고 싶을 때는
getline()
함수를 사용해야 한다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string name, subject;
cout << "자신의 이름을 적어주세요: ";
getline(cin, name);
cout << "가장 자신있는 과목을 적어주세요: ";
getline(cin, subject);
cout << name << "님이 가장 자신있어 하는 과목은 바로 "
<< subject << "입니다!" << endl;
return 0;
}
// 자신의 이름을 적어주세요: 홍길동 (입력)
// 가장 자신있는 과목을 적어주세요: 국어 (입력)
// 홍길동님이 가장 자신있어 하는 과목은 바로 국어입니다!
getline()
함수는 첫 번째 매개변수로cin
객체를, 두 번째 매개변수로 문자열을 저장할string
객체 변수를 전달 받는다.
4. string
메서드
string
메서드는string
클래스에 정의된 문자열과 관련된 작업을 할 때 사용하는 메서드이다.string
클래스에서 제공하는 대표적인 문자열 처리 함수는 다음과 같다.
1] length()
와 size()
2] append()
3] find()
4] compare()
5] replace()
6] capacity()
와 max_size()
1) length()
와 size()
메서드
length()
메서드는 문자열의 길이를 반환하는 메서드이다.size()
메서드도length()
메서드와 언제나 같은 값을 반환하지만, 그 의미는 약간 다르다.
- 다음과 같이
length()
메서드는 문자열의 길이를 나타내지만,size()
메서드는 해당string
객체가 메모리에서 실제 사용하고 있는 크기를 나타낸다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1;
string str2 = "C++ Programming";
cout << "문자열 str1의 길이는 " << str1.length() << "입니다." << endl;
cout << "문자열 str2의 길이는 " << str2.size() << "입니다." << endl;
return 0;
}
// 문자열 str1의 길이는 0입니다.
// 문자열 str2의 길이는 15입니다.
2) append()
메서드
append()
메서드는 하나의 문자열의 끝에 다른 문자열을 추가하는 메서드이다.
append()
메서드를 위한 원형은 다음과 같다.
1. 문자열.append(추가할문자열); // 추가할 문자열을 맨 끝에 추가함
2. 문자열.append(추가할문자열, 시작위치, 개수); // 추가할 문자열의 시작 위치부터 개수만큼만 맨 끝에 추가함
3. 문자열.append(개수, 추가할문자); // 추가할 문자를 개수만큼 맨 끝에 추가함
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1, str2, str3;
str1.append("C++ Programming");
str2.append("C++ Programming", 4, 7);
str3.append(4, 'X');
cout << str1 << endl;
cout << str2 << endl;
cout << str3 << endl;
return 0;
}
// C++ Programming
// Program
// XXXX
3) find()
메서드
find()
메서드는 특정 문자열을 찾아, 그 시작 위치를 반환하는 메서드이다.
find()
메서드를 위한 원형은 다음과 같다.
1. 문자열.find(찾을문자열); // 인덱스 0부터 찾을 문자열을 찾아, 그 시작 위치를 반환함
2. 문자열.find(찾을문자); // 인덱스 0부터 찾을 문자를 찾아, 그 시작 위치를 반환함
3. 문자열.find(찾을문자열, 시작위치); // 시작 위치부터 찾을 문자열을 찾아, 그 시작 위치를 반환함
find()
메서드는 해당 문자열에서 찾을 문자열을 찾지 못하면,string::size_type
의string::npos
라는 상수를 반환한다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "C++ Programming";
cout << str.find("Pro") << endl;
cout << str.find('r') << endl;
if (str.find("Pro", 5) != string::npos) {
cout << "해당 문자열을 찾았습니다." << endl;
} else {
cout << "해당 문자열을 찾지 못했습니다." << endl;
}
return 0;
}
// 4
// 5
// 해당 문자열을 찾지 못했습니다.
- 정적 상수인
string::npos
는string
클래스에static const size_type = -1
로 명시되어 있다.
4) compare()
메서드
compare()
메서드는 두 문자열 간의 내용을 비교하는 메서드이다.
compare()
메서드의 반환값이 참(true
)이 되는 경우는 다음과 같다.
1. str1.compare(str_02) == 0 // str1과 str2이 같을 경우
2. str1.compare(str_02) < 0 // str1이 str2보다 사전 편찬순으로 앞에 있을 경우
3. str1.compare(str_02) > 0 // str1이 str2보다 사전 편찬순으로 뒤에 있을 경우
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "ABC";
string str2 = "ABD";
if (str1.compare(str2) == 0) {
cout << str1 << "이 " << str2 << "와 같습니다." << endl;
} else if (str1.compare(str2) < 0) {
cout << str1 << "이 " << str2 << "보다 사전 편찬 순으로 앞에 있습니다." << endl;
} else {
cout << str1 << "이 " << str2 << "보다 사전 편찬 순으로 뒤에 있습니다." << endl;
}
return 0;
}
// ABC이 ABD보다 사전 편찬 순으로 앞에 있습니다.
5) replace()
메서드
replace()
메서드는 특정 문자열을 찾아, 그 문자열을 다른 문자열로 대체하는 메서드이다.
replace()
메서드를 위한 원형은 다음과 같다.
- 다음의 코드는 문자열에서
"nice"
라는 문자열을 찾아,"awesome"
으로 바꾸는 것이다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "C++ is very nice!";
string str2 = "nice";
string str3 = "awesome";
string::size_type index = str1.find(str2);
if (index != string::npos) {
str1.replace(index, str2.length(), str3);
}
cout << str1 << endl;
return 0;
}
// C++ is very awesome!
- 위의 코드처럼
replace()
메서드를 사용하기 전에 우선find()
메서드를 사용하여 해당 문자열이 존재하는지를 파악하는 것이 좋다.
6) capacity()
와 max_size()
메서드
capacity()
메서드는 해당 문자열이 재대입(Reallocation) 받지 않고 저장할 수 있는 최대 문자열의 길이를 반환한다.max_size()
메서드는 해당 문자열이 최대한 대입 받으면 가질 수 있는 최대 문자열의 길이를 반환한다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "C++ Programming";
cout << "문자열 str의 length는 " << str.length() << "입니다." << endl;
cout << "문자열 str의 capacity는 " << str.capacity() << "입니다." << endl;
cout << "문자열 str의 max_size는 " << str.max_size() << "입니다." << endl;
return 0;
}
// 문자열 str의 length는 15입니다.
// 문자열 str의 capacity는 22입니다.
// 문자열 str의 max_size는 18446744073709551599입니다.