기초 공부/자료구조

[C++] STL string 정리 및 사용법

기개 2022. 4. 28. 14:05

안녕하세요 기회개발자 기개 입니다.

오늘은 C++에서 char 배열 대신 자주 사용하는 string에 대해 소개해보려고 합니다.

앞서서 배열과 vector를 비교했는데요, vector와 string은 꽤나 유사합니다.

 

왜 char 배열 대신 string을 사용할까요?

우선, char 배열과 string의 비교가 필요할 것 같습니다.

char 배열과 비교해서 sring의 장점이 무엇인지, 어떤 상황에서 사용하면 좋을지를 알아본 후 사용법에 대해 알아봅시다.

 

1. char 배열과 string의 비교

1) 메모리 상의 비교

char 배열은 크기를 처음에 할당하기에 크기가 고정입니다.
하지만 string은 넣어주는 데이터 양 만큼 변하기에 크기가 동적입니다.


2) 삽입 및 삭제

char 배열과 string 모두 삽입과 삭제가 쉽고 간편하지가 않습니다.
데이터를 삽입할 경우 해당 위치에 뒤에 있던 기존에 있던 데이터들을 모두 한칸 씩 뒤로 이동시켜줘야 합나다.
데이터를 삭제할 경우 해당 위치에 뒤에 있던 기존에 있던 데이터들을 모두 한칸 씩 앞으로 이동시켜줘야 합니다.
하지만 string의 경우 내장함수를 사용하면 그리 어렵지가 않습니다.


3) 인덱스로 접근이 가능

char 배열과 string 모두 순차적으로 데이터가 존재하기 때문에 인덱스를 통해서 데이터에 접근이 가능합니다.

 

2. 어떤 상황에서 string을 사용하는게 좋을까

1) 저장할 데이터의 개수가 자주 변할 경우

char 배열의 경우 저장할 데이터의 개수를 처음에 정해줘야 합니다.
char 배열의 공간을 크게 잡아줄 경우 개수가 자주 변해도 이에 대처가 가능하지만, 메모리를 계속 차지하기에 좋다고 볼 수 없습니다.
string에 경우 넣어주는 데이터의 수만큼 메모리를 차지하기에 메모리를 관리해주기 좋다고 볼 수 있습니다.


2) 데이터들 중간에 삽입과 삭제가 적을 경우

앞서서 string도 char 배열과 같이 순차적으로 데이터를 삽입하기 때문에 삽입이나 삭제가 있을 경우 기존의 데이터를 이동시켜줘야 합니다.
vector의 경우 erase()와 insert()와 같이 쉽게 삽입과 삭제가 가능하지만,
기존의 데이터를 이동시켜줘야 하는 점이 있기에 O(N)의 시간을 소요하게 됩니다.
list 같은 경우 O(1)이 걸리기 때문에 string이 삽입과 삭제에서 시간적으로 장점이 없다는 것을 알 수 있습니다.


3) 데이터 검색이 적을 경우

데이터들이 순차적으로 삽입되어 있기에 데이터를 검색하는데 O(N)이 걸리게 됩니다.
Hash 같은 경우 O(1)이 걸리기 때문에 string이 검색에서 시간적으로 장점이 없다는 것을 알 수 있습니다.


4) 인덱스로 값에 접근하고 싶을 경우

인덱스로 값의 접근이 편리하기 때문에, 랜덤하게 값에 접근할 경우 좋다고 볼 수 있습니다.

 

3. string의 사용법 (내장함수)

string에는 데이터의 삽입, 삭제, 접근 등을 편하게 하기 위한 내장함수들이 존재합니다.

기본적으로 string을 선언하는 방법을 살펴보고 자주 사용하는 내장함수들에 대해서 알아봅시다.

#include <string>

using namespace std; // STL을 사용할 때 선언해주면 사용하기 편리합니다.

string s;

 

1) 데이터의 삽입

데이터들이 순차적으로 삽입되기 때문에 마지막에 삽입된 데이터 뒤에 삽입을 합니다.

s = "abcde";
s += "f";
s.push_back('g') // 결과 {'a', 'b', 'c', 'd', 'e', 'f', 'g'}

 

2) 데이터의 삭제

데이터들이 순차적으로 삽입되기 때문에 마지막에 삽입된 데이터를 삭제합니다.

s.pop_back(); // 가장 마지막에 삽입했던 'g'가 삭제됩니다.

 

 

3) 데이터의 접근

string은 인덱스로 데이터에 접근이 가능하지만,

순차적으로 데이터를 삽입하기에 데이터의 맨 앞과 맨 뒤를 접근할 수 있는 내장함수가 존재합니다.

front() | string에 가장 먼저 삽입된 데이터를 알려줍니다.

s.front(); // 'a'를 반환해 줍니다.

back() | string에 가장 마지막에 삽입된 데이터를 알려줍니다.

s.back(); // 'f'를 반환해 줍니다.

begin() | string에 가장 먼저 삽입된 데이터를 포인터로 가르킵니다.

s.begin(); // 'a'의 위치를 가르킵니다. *s.begin() == s.front()

end() | string에 가장 마지막에 삽입된 데이터의 뒤를 포인터로 가르킵니다.

s.end(); // string의 끝을 가르킵니다. *(s.end() - 1) == s.back()

 

4) (활용) 중간에 존재하는 데이터의 검색 후 삽입과 삭제

string의 경우 iterator라는 순환자를 사용해 데이터를 참조(포인터)합니다.

이를 활용하여 내장함수인 erase와 insert로 중간에 삭제나 삽입을 할 수 있습니다.

erase와 insert를 하면 알아서 기존에 있던 데이터들을 한 칸씩 앞으로 또는 뒤로 이동을 시켜줍니다.

string id = 'b'; // 찾고자 하는 데이터
for(auto it = s.begin(); it != s.end(); ++it) {
	if(*it == id) {
    	s.erase(it); // (위치) 결과 {'a', 'c', 'd', 'e', 'f'} | it - s.begin()은 index 반환(1 반환)
    }
}
string id2 = "c"; // 찾고자 하는 데이터
for(auto it = s.begin(); it != s.end(); ++it) {
	if(*it == id2) {
    	s.insert(it, "b"); // (위치, 삽입할 데이터) 결과 {'a', 'b', 'c', 'd', 'e', 'f'}
    }
}

string에는 iterator를 쓰지 않고, find()라는 내장함수가 있어 이것으로도 원하는 위치를 찾을 수 있습니다.

이것에 관해서는 아래에서 설명하겠습니다.

 

5) 이외에 유용한 내장함수

string에 데이터가 있는지, 몇 개의 데이터를 가지고 있는지를 알 수 있는 내장함수가 있습니다.

또한 string를 초기화 해줄 수 있는(모든 데이터를 없애주는) 내장함수도 있습니다.

s.empty(); // 데이터가 존재한다면 0 반환, 존재하지 않는다면 1 반환
s.size(); // 데이터의 갯수 반환 | 결과 6
s.clear(); // 초기화 | 결과 {} | 예제에는 적용하지 않음.

string의 일정 부분만 떼어낼수도 있고, 원하는 문자열이 있는지 찾을 수도 있습니다.

s.substr(1,4); // "bcde"
s.find("cde"); // 해당하는 문자열이 없다면 -1 반환, 있다면 찾는 문자열 첫 글자의 인덱스 반환 | 결과 2

문자열이 숫자로 이뤄져 있다면 int형으로 바꿀 수 있습니다.

string str = "12345";
int a = atoi(str); // a = 12345

// 문자열에 있는 하나만 int 형으로 변환하는 경우
string tmp = str[1]; // index를 포함하고 있기에 선언과 할당을 분리해줘야 함
int b = atoi(tmp); // b = 2

int 형도 문자열로 바꿀 수 있습니다.

int c = 123;
string str2 = to_string(c); // 결과 {'1', '2', '3'}

대문자를 소문자로, 소문자를 대문자로 바꿀 수도 있습니다.

string s2 = "abcde"
toupper(s2) // 결과 {'A', 'B', 'C', 'D', 'E'}
tolower(s2[1]) // 결과 {'A', 'b', 'C', 'D', 'E'}

숫자인지 문자인지도 구분할 수 있습니다. (한 글자씩만 구분 가능)

string s3 = "1aBCd2e34";
isdigit(s3[0]) // 숫자일 경우 1반환, 숫자가 아닐 경우 0 반환 | 결과 1
isalpha(s3[1]) // 문자일 경우 1반환, 문자가 아닐 경우 0 반환 | 결과 1

 

6) char 배열과 string 변환

① char 배열을 string으로

char arr[] = "abcdefg1234";
string s4 = arr;

 

② string을 char 배열로

string s5 = "abcdefgh";
char ch[100];

strcpy(ch, s5.c_str());