C++ string 사용법 및 기능정리(동작방식)
C++에는 string이란 클래스가 있습니다.
이걸 사용하려면 string 헤더파일을 선언해 줘야 하며 다양한 기능을 제공합니다.
그렇다면 string이란 녀석이 왜 생겨났을까??
기존 C언어에서 문자열 처리를 하려면 상당히 골치 아팠습니다. 특히 가변 길이를 처리할때요.
프로그래머가 손수 메모리를 재 할당 해주거나 그게 아니라면 충분한 문자열 배열을 선언해주거나...
너무 번거롭고 나중에 문제생길 것들이 많았죠... 예상치 못한 결과도 초래했다고 합니다.
그래서 C++에서는 class로 문자열을 감싸고 public을 통해 쉽게 사용할 수 있도록 정의하고 만들었습니다.
그래서 C++은 문자열 사용을 기본적으로 string으로 하고 있습니다.
그렇다면 string에 사용법에 대해 알아보도록 하겠습니다.
String 초기화
string s | s 라는 string변수 선언 |
string s("Hwan") | s 변수를 "Hwan"이라는 값으로 초기화 |
string s = "Hwan" | s 변수를 "Hwan"이라는 값으로 초기화 |
string s.assign() | string s("Hwan") 과 동일한 기능 |
/////////////////////////////////////////////////////////
string s; //변수 선언
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
string s = "Hwan"; //output : Hwan
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
string s1("Hwan"); //output : Hwan
string s2(4, 'A'); //output : AAAA
string s3(s1, 0, s1.length() - 2); //output : HW
string s4(s1, 2, s1.length()); //output : an
string s5(s2); //output : AAAA
string s6("ABCDE", 3); //output : ABC
char c[] = "TEST Code!!";
string s7(c); //output : TEST Code!!
/////////////////////////////////////////////////////////
String Element access(String 요소 접근)
s.at(숫자) | string 문자열의 i번째 참조(범위검사 함) |
s.[숫자] | string 문자열의 i번째 참조(범위검사 안함) |
s.front() | string 문자열의 첫번째 요소 반환(char type) |
s.back() | string 문자열의 마지막 요소 반환(char type) |
s.c_str() | string 문자열을 const char* 로 접근할 수 있도록 해줌('\0' 문자 포함) |
string s = "ABCDE123";
cout << s.at(2) << endl; //output : C (범위가 맞지 않으면 예외처리를 함)
cout << s[0] << endl; //output : A
cout << s.front() << endl; //output : A
cout << s.back() << endl; //output : 3
const char * c = s.c_str(); //배열로써 접근이 가능하며 '\0'에 접근이 가능하다.
cout << c << endl; //output : ABCDE123
cout << (c_arr == s) ? true : false; //output : 1(true)
cout << (&(c_arr[0]) == &(s[0])) ? true : false; //output : 1(true)
string에서의 at과 []의 차이점은 범위검사를 통한 예외처리입니다. 백터와 같은데 at은 범위검사를 하고 해당 범위 이외의 값이 들어오면
std::out_of_range를 발생시킵니다.
반면 []는 범위검사를 하지 않으며, 예외처리가 아닌 VC++ or g++의 디버깅이 일어나게 됩니다.
String Iterator
s.begin() | string의 시작 주소 반환 |
s.end() | string의 (마지막 + 1) 주소 반환 |
s.rbegin() | string의 마지막 주소를 반환 |
s.rend() | string의 (첫번 째 - 1 ) 주소 반환 |
string s = "ABCDE123";
string::iterator iter = s.begin();
string r_s, cp;
for (; iter != s.end(); iter++) {
cout << *iter;
if (*iter == 'E')
break;
} //output : ABCDE
copy(s.rbegin(), s.rend(), back_inserter(r_s));
copy(s.begin(), s.end(), back_inserter(cp));
cout << r_s << endl; //output : 321EDCBA
cout << (s == r_s) ? true : false; //output : 0(false)
cout << (s == cp) ? true : false; //output : 1(true)
cout << (&(s[0]) == &(cp[0])) ? true : false; //output : 0(false)
String의 iterator에 대한 사진입니다.
출처 : https://en.cppreference.com/w/cpp/string/basic_string/rbegin
String Capacity (용량 확인)
s.empty() | string이 비어있으면 true, 아니면 false 반환 |
s.size(), s.length() | string에 들어있는 요소에 대한 길이 반환 |
s.capacity() | string에 할당된 실제 크기 반환 |
s.max_size() | string에 할당될 수 있는 최대 메모리 크기 반환 |
s.reserve(숫자) | 해당 숫자만큼 capactiy 길이를 설정 |
s.shrink_to_fit() | 잉여 capacity 공간을 조절해 준다. |
string s = "ABCDE123";
cout << s.length() << endl; //output : 8
cout << s.size() << endl; //output : 8
cout << s.capacity() << endl; //output : 15
s.reserve(100);
cout << s.size() << endl; //output : 8
cout << s.capacity() << endl; //output : 111
s.shrink_to_fit();
cout << s.capacity() << endl; //output : 15
string은 기본적으로 capacity의 크기를 15로 맞춰주고 있습니다.
또한 reserve를 통해 capacity의 크기를 늘려도 100이 아닌 111인걸 볼 수 있습니다.
string은 이렇듯 설정한 크기보다 좀 더 여유있는 메모리 공간을 갖게 됩니다.
이는 vector의 메모리 할당부분과 다릅니다.
String Operations (String의 기능)
s.clear() | s에 있는 값들을 지워준다. (size = 0) |
s.insert() | s에 사용자가 원하는 위치에 문자 삽입 가능 |
s.erase() | s문자열 중 사용자가 원하는 부분 삭제 |
s.push_back() | s문자열 뒤에 단어 추가. (문자열 X, 문자 O) |
s.pop_back() | s문자열 맨 뒤 단어 하나 삭제. (s.size() - 1) |
s.operator += | 문자열 뒤에 문자열 추가 가능 |
s.append() | 문자열 뒤에 문자열 추가 가능 |
s.compare() | 문자열 비교 함수 |
s.replace() | 문자열 수정 |
s.substr() | 문자열 중 원하는 부분을 잘라서 넘겨준다. |
s.copy() | s문자열을 (char [])형식의 배열 변수에 복사 |
s.resize() | s문자열 길이를 수정 |
s.swap() | s문자열과 다른 문자열을 서로 바꿈 |
s.starts_with(문자열) | s문자열에 대해 입력한 문자열이 시작 위치부터 동일한지 여부 |
s.ends_with(문자열) | s문자열에 대해 입력한 문자열이 끝 위치부터 동일한지 여부 |
string s = "ABCDE123"
s.insert(0, "TEST"); //output : TESTABCDE123
s.insert(s.begin() + s.find_first_of('D') + 1, ':'); // output : TESTABCD:123(문자만 가능)
////////// (compare) s = TESTABCD:123 /////////////
s.compare("TESTABCD:123"); //output : 0
s.compare("a"); //output : -1
s.compare("X"); //output : -1
s.compare("BBBBBBBBBBBBBBB"); //output : 1
s.compare("100000000000000000000000"); //output : 1
s.compare("VVVVV"); //output : -1
////////// (erase) s = TESTABCD:123 /////////////
s.erase(0, 4); //output : ABCD:123
s.erase(find(s.begin(), s.end(), 'D')); //output : ABC:123('D'만 지움)
s.erase(s.find(':')); //output : ABC(':'부터 뒤 문자까지 모두 지움)
////////// (push, pop) s = ABC /////////////
s.push_back('S'); //output : ABCS
s.pop_back(); //output : ABC
////////// (append) s = ABC /////////////
s.append("TEST"); //output : ABCTEST
s.append(1, '1'); //output : ABCTEST1
s.append("123456789", 3, 3); //output : ABCTEST1456
////////// (clear) s = ABCTEST1456 /////////////
const char c[] = "Hwan";
s.append(c); //output : ABCTEST1456Hwan
s += c; //output : ABCTEST1456HwanHwan(capacity() = 15 -> 31)
s.clear(); //s.size() = 0, s.capacity() = 31
////////// (replace) s = '' /////////////
s.append("ABCD123"); //output : ABCD123
s.replace(4, 2, "Hwan"); //output : ABCDHwan3
s.replace(s.find('H'), s.size() - s.find('H'), "WOW"); //output : ABCDWOW
////////// (substr) s = ABCDWOW /////////////
string temp = s.substr(4); //output : WOW;
temp = s.substr(3, 2); //output : DW;
temp = s.substr(s.size() - 3, 50); //output : WOW;
////////// (copy) s = ABCDWOW /////////////
char arr[5]{};
s.copy(arr, sizeof arr - 1); //output : ABCD (마지막 '\n' 포함)
////////// (resize) s = ABCDWOW /////////////
s.resize(100); //output : ABCDWOW, s.size() = 100, s.capacity() = 111
s.resize(4); //output : ABCD, s.size() = 4, s.capacity() = 15
////////// (swap) s = ABCD /////////////
string sw = "AAA";
s.swap(sw); //s = "AAA", sw = "ABCD"
/////////// c++ 20 ///////////////////
s = "hello Hwan";
s.starts_with("hello"); //output : true;
s.starts_with('h'); //output : true;
s.starts_with("Hwan"); //output : false;
s.starts_with('x'); //output : false;
s.ends_with("Hwan"); //output : true;
s.ends_with('n'); //output : true;
s.ends_with("hello"); //output : false;
s.ends_with('q'); //output : false;
compare의 경우 문자가 같으면 0을 반환합니다.
반대로 다를경우 1 or -1 을 반환하는데 조건은 다음과 같습니다.
문자열 기준 '숫자 < 대문자 < 소문자' 순으로 크기를 비교합니다.
그래서 비교 문자중 자신이 더 크면 1을 반환, 작으면 -1을 반환합니다.
※string 같은경우 삽입하거나 지울 때 하나씩 일일이 옮기는 작업을 하게 됩니다. 즉 O(n)입니다.
또한 삽입중 capacity()값보다 크게 증가될 경우 reallocate이 발생하게 됩니다.
따라서 삽입과 삭제는 되도록 하지 않는것이 좋습니다.
String Search (문자 찾기)
find(문자 or 문자열) | 찾은 index값을 정수형태로 넘겨준다. 못찾으면 -1을 반환 |
rfind(문자 or 문자열) | find와 동일하지만 뒤에서부터 찾는다. |
find_first_of(문자 or 문자열) | 문자 or 문자열 중 첫 index부터 검색해서 하나라도 맞으면 해당 index 값을 반환. 못찾으면 쓰레기값 반환(npos) |
find_first_not_of(문자 or 문자열) | 문자 or 문자열 중 첫 index부터 검색해서 없는 값을 찾아내 해당 index를 반환. 모두 포함되 있다면 -1 반환 |
find_last_of(문자 or 문자열) | 문자 or 문자열 중 마지막 index부터 검색해서 하나라도 맞으면 해당 index 값을 반환. 못찾으면 쓰레기값 반환(npos) |
find_last_not_of(문자 or 문자열) | 문자 or 문자열 중 마지막 index부터 검색해서 없는 값을 찾아내 해당 index를 반환. 모두 포함되 있다면 -1 반환 |
string s = "ABCD 123 abc";
s.find('C'); //output : 2
s.find("CD"); //output : 2
s.find("CDEF"); //output : npos
s.find(' ', 6); //output : 8
s.rfind(' '); //output : 8
s.find_first_of('1'); //output : 5
s.find_first_of(' '); //output : 4
s.find_first_of('x'); //output : npos
s.find_last_of('3'); //output : 7
s.find_last_of(' '); //output : 8
s.find_first_not_of("ABCDEFG1234567abcdef"); //output : 4
s.find_first_not_of("ABCDEFG1234567abcdef "); //output : -1
s.find_last_not_of("ABCDEFG1234567abcdef"); //output : 8
s.find_last_not_of("ABCDEFG1234567abcdef "); //output : -1