[전문가를 위한 C++] 스트링과 스트링 뷰 다루기
‘전문가를 위한 C++ - Marc Gregoire 지음, 남기혁 옮김’ 책을 참고하여 작성한 포스트입니다.
동적 스트링
C 스타일 스트링
- C언어에서 스트링은 널 문자(
\0
, NUL)로 끝나는 문자배열로 표현됐다. - 이는 버퍼 오버플로(buffer overflow)를 비롯한 다양한 문제로 보안 취약점이 드러날 수 있다.
- 실제 메모리에 저장될 때 문자의 개수에 널 문자를 위한 자리 하나를 더 포함한 공간이 필요하다.
strlen()
은 문자의 개수를 반환하므로,strcpy()
를 하기 위해 배열을 새로 할당할 때strlen()
에 1을 더한 크기의 공간을 할당하여야 한다.sizeof()
의 경우는 스트링의 크기를 구할 때 절대로 사용하면 안된다.- 리턴 값이 C스트링이 저장된 방식에 따라 다르다.
char[]
로 저장한 경우는 널문자를 포함하여 반환하므로, 실제 할당된 메모리 크기이다.char*
로 저장한 경우는 포인터의 크기를 반환한다. 32비트 모드면 4,64비트 모드에서 컴파일하면 8을 반환한다.
- 리턴 값이 C스트링이 저장된 방식에 따라 다르다.
- C 스트링 관련 함수들은
<cstring>
헤더 파일에 정의되어 있다.
스트링 리터럴(string literal)
- 변수에 담지 않고 곧바로 값으로 표현한 스트링.
- 메모리의 읽기 전용 영역에 저장된다.
- 따라서, 같은 스트링 리터럴이 코드에 여러 번 나오면 이에 대한 레퍼런스를 재활용하는 방식으로 메모리를 절약한다. 이를 리터럴 풀링(literal pooling)이라 부른다.
- 스트링 리터럴을 변수에 대입할 수 있지만, 동일한 리터럴을 여러 곳에서 공유할 수 있기 때문에 변수에 저장하면 위험하다.
- c++ 표준에서는 스트링 리터럴을 ‘const char가 n개인 배열’ 이라 정의하고 있지만, 다수의 컴파일러는 const char* 타입 변수에 저장하지 않는다.
- 해당 리터럴을 변경하지 않는다면 상관 없겠지만, 그러지 않다면 예측할 수 없는 문제들이 발생할 수 있다.
- 그래서 스트링 리터럴을 참조할 때는 const 문자에 대한 포인터를 사용하는 것이 훨씬 안전하다.
const char* ptr { "Hello" }; ptr[0] = 'a'; // 에러 발생
- 문자 배열(
char[]
)의 초깃값 설정 시에 스트링 리터럴을 사용한다. 이때 컴파일러는 주어진 스트링을 담을 수 있게 충분히 큰 배열을 생성한 뒤 여기에 실제 스트링 값을 복사한다. - 이렇게 만들어진 스트링 리터럴은 읽기 전용 메모리에 넣어지지 않으며, 따라서 재활용되지 않는다.
로 스트링 리터럴(raw string literal)
- 여러 줄에 걸쳐 작성하는 스트링 리터럴
R"( 스트링 )"
의 형식이다.- 이스케이프 시퀀스가 무시된다. 스페이스나 엔터 그냥 쓰면 된다.
C++ std::string 클래스
- std 네임스페이스에 속하며,
<string>
헤더에 속해 있다.string 클래스 사용법
- 클래스지만 마치 기본 타입인 것처럼 사용한다.
- 메서드 중
compare()
는 값이 같은 경우에 0을 반환하고, 다른 경우에는 0이 아닌 값을 리턴한다. - 그래서 두 스트링 비교는
==
사용하는 것이 좋다. - 메모리 관련 작업은 string 클래스가 알아서 처리해 준다.
- 그리고 string 객체는 스택 변수로 생성되므로, 메모리 누수가 발생하지 않는다.
- 다음과 같은 연산들이 있다.
substr(pos, len)
- 인수로 지정한 시작 위치와 길이에 맞는 서브스트링 리턴
find(str)
- 인수로 지정한 서브스트링이 있는 지점을 리턴. 없으면
string::npos
반환하고
- 인수로 지정한 서브스트링이 있는 지점을 리턴. 없으면
replace(pos, len, str)
- 스트링에서 인수로 지정한 위치와 길이에 해당하는 부분을 str로 지정한 값으로 교체
숫자 변환
하이레벨 숫자 변환
숫자를 string으로 변환
- string 객체를 새로 생성해서 리턴하며, 메모리 할당 작업도 처리해준다.
string to_string(T val);
long double d { 3.14L };
string s { to_string(d) };
string을 숫자로 변환
- 다음 함수 매개변수의 idx는 변환되지 않은 부분의 맨 앞에 있는 문자의 인덱스를 가리키는 포인터,
- base는 변환할 수의 밑(base, 기수, 기저)이다.
- idx 포인터를 널 포인터로 지정하면 이 값을 무시한다.
- 변환함수들은 제일 앞에 나온 공백 문자를 무시하고, 변환에 실패하면
invalid_argument
를, 리턴 타입의 범위를 벗어나면out_of_range
예외를 던진다.
int stoi(const string& str, size_t *idx=0, int base=10);
long long stol(...);
float stof(...);
double stod(...);
const string MyString {" 123A"};
size_t Idx { 0 };
int Value { stoi(MyString, &Idx) };
// Value : 123
// MyString[Idx] : 'A'
- base 값을 0으로 주면 0x, 0X는 16진수, 0으로 시작하는 숫자는 8진수, 나머지는 10진수로 처리한다.
로우 레벨 숫자 변환 (추가하기)
std::string_view 클래스 (추가하기)
- 읽기 전용 스트링에 효과적이다.
스트링 포맷 지정
- c++20
Leave a comment