[전문가를 위한 C++] 2장 : 스트링과 스트링 뷰 다루기
2026. 2. 23. 23:50
2.1 동적 스트링
c를 사용 -> null로 끝나는 문자 배열로 스트링을 표현
c++ -> buffer overflow 문제 발생 가능. std::string 클래스 제공
2.1.1 c스타일 스트링
char* copyString(const char* str) {
char* result { new char{strlen(str) + 1}};
strcpy(result, str);
return result;
}
char* copyString(const char* str1, const char* str2) {
char* result { new char{strlen(str1) + strlen(str2)+ 1}};
strcpy(result, str1);
strcat(result, str2);
return result;
}
- sizeof() : 데이터 타입/변수의 크기 return
const char* text {"abcdef"};
size_t s3 {sizeof(text2)}; // 32비트 모드에서는 4, 64비트 모드에서는 8
size_t s4 {sizeof(text2)}; // 6
2.1.2 스트링 리터럴
cout << "hello" << endl;
- "hello" 처럼 변수에 담지 않고 곧바로 값으로 표현한 스트링을 스트링 리터럴이라 부른다.
- 메모리의 읽기 전용 영역에 저장
- 컴파일러는 같은 스트링 리터럴이 코드에 여러 번 나오면 이에 대한 레퍼런스를 재활용하는 방식으로 메모리를 절약
- 이를 리터럴 풀링(literal pooling이라 부른다
- 스트링 리터러를 변수에 대입할 수는 있지만, 스트링 리터럴은 메모리의 읽기 전용 영역 뿐만 아니라 동일한 리터럴을 여러 곳에서 공유할 수 있기 때문에 변수에 저장하면 위험하다.
char* ptr {"hello"}; // 변수에 스트링 리터럴을 대입
ptr[1] = 'a'; // 결과를 예측할 수 없다.
const char* ptr {"hello"}; // 변수에 스트링 리터럴을 대입
ptr[1] = 'a'; // 컴파일 에러
char arr[] {"hello"}; // 컴파일러는 적절한 크기의 문자 배열 arr을 생성한다
arr[1] = 'a'; // 이제 스트링을 수정할 수 있다.
1 Raw String Literal
const char* str {"Hello "World"!"}; // 에러
const char* str {"Hello \"World\"!"};
const char* str {R"(Hello "World"!)"};
- Raw String Literal은 ")"로 끝나기 때문에 이 구문을 사용하는 스트링 안에 ")"를 넣을 수 없다.
2.1.3 C++ std::string 클래스
1 C 스타일 스트링의 문제점
- 장점
- 간단하다. 내부적으로 기본 문자 타입과 배열 구조체로 처리한다.
- 가볍다. 제대로 사용하면 메모리를 꼭 필요한 만큼만 사용
- 로우 레벨. 메모리의 실제 상태를 조작하거나 복사하기가 쉽다
- 단점
- 스트링 데이터 타입에 대한 고차원 기능을 구현하려면 상당한 노력 필요
- 찾기 힘든 메모리 버그
2 string 클래스 사용법
string a{"12"}; string b{"34"}; string c; c = a + b;
스트링 비교
char* a {"12"};
char b[] {"12"};
if(a==b) { // 항상 false return
}
if(strcmp(a,b) == 0) // 0보다 작은값, 0, 0보다 큰 값을 리턴
string a{"12"};
string b{"34"};
auto result {a.compare(b)};
if(result < 0) {cout << "less" << endl;}
if(result > 0) {cout << "greater" << endl;}
if(result == 0) {cout << "equal" << endl;}
메모리 처리
연산자 오버로딩으로 string을 확장해도 메모리 관련 작업은 string 클래스가 알아서 처리해준다는 것을 알 수 있다. 따라서 메모리 overrun이 발생할 걱정을 할 필요가 없다.
string 객체는 모두 스택 변수로 생성. string 클래스를 사용하면 메모리를 할당하거나 크기를 조절할 일이 상당히 많긴 하지만 string 객체가 스코프를 벗어나자마자 여기에 할당된 메모리를 string 소멸자가 모두 정리한다.
C 스트링과 호환
- string 클래스에서 제공하는 c_str() 메서드를 사용하면 c언어에 대한 호환성을 보장할 수 있다. 이 메서드는 c 스트링을 표현하는 const 포인터를 return한다.
스트링 연산
- substr(pos, len) : 인수로 지정한 시작 위치와 길이에 맞는 서브스트링을 리턴한다.
- find(str) : 인수로 지정한 서브스트링이 있는 지점을 리턴한다.
- replace(pos, len, str) : 스트링에서 인수로 지정한 위치와 길이에 해당하는 부분을 str로 지정한 값을 교체한다.
- starts_with(str)/ends_with(str) : 인수로 지정한 서브스트링으로 시작하거나 끝나면 true를 리턴한다.
3 std::string 리터럴
- 표준 사용자 정의 리터럴s를 사용하려면 std::literals::string_literals 네임스페이스를 추가한다.
auto string1 {"Hello World"}; // string1의 타입은 const char* auto string2 {"Hello World"s}; // string2의 타입은 std::string
// 다음 중 하나로 작성해도된다
using namespace std;
using namespace std::literals;
using namespace std::string_literals;
using namespace std::literals::string_literals;
- 기본적으로 인라인 네임스페이스에 선언된 것은 모두 자동으로 부모 네임스페이스에도 추가된다.
#### 4 std::vector와 스트링의 CTAD
```cpp
vector names {"John", "Sam", "Joe"}; // vector<const char*>로 추론
vector names{"John"s, "Sam"s, "Joe"s}; // 각 스트링 리터럴 끝에 s를 붙인다2.1.4 숫자 변환
1 하이레벨 숫자 변환
숫자를 string으로 변환
string to_string(T val);
2 로우 레벨 숫자 변환
- 로우 레벨 숫자 변환에 대한 함수도 다양하게 제공 <charconv> 헤더에 정의
- 고성능과 로케일 독립성에 최적화
- 하이레벨 숫자 변환 함수에 비해 처리 속도가 엄청나게 빠르다
- 퍼펙트 라운드 트리핑 방식으로 설계되었다
to_chars_result to_chars(char* first, char* last, IntegerT value, int base = 10);
from_chars_result from_chars(const char* first, const char* last, IntegerT& value, int base = 10);
2.1.5 std::string_view 클래스
- c++17 이전에는 읽기 전용 스트링을 받는 함수의 매개변수 타입을 쉽게 결정할 수 없었다.
- const char*로 지정하면 std::string을 사용할 때 c_str()이나 data()로 const char*를 구해야 한다.
- 더 심각한 문제는 이렇게 하면 std::string의 객체지향 속성과 여기서 제공하는 헬퍼 메서드를 제대로 활용할 수 없다.
- 매개변수로 const std::string&으로 지정하면? 그렇게 하면 항상 std::string만 사용해야 함.
- 스트링 리터럴을 전달하면 컴파일러는 그 스트링 리터럴의 복사본이 담긴 string 객체를 생성해서 함수로 전달하기 때문에 오버헤도가 발생
- c++에서 추가된 std::string_view 클래스를 사용하면 고민 해결
- string_view는 실제로 const string& 대신 사용할 수 있으며 오버헤드도 없다
string_view extractExtension(string_view filename) { return filename.substr(filename.rfind('.')); }
- string_view는 실제로 const string& 대신 사용할 수 있으며 오버헤드도 없다
1 std::string_view와 임시 스트링
- 임시 스트링에 대한 view를 절대로 std::string_view로 지정하면 안된다
2 std::string_view 리터럴
auto sv {"My string_view"sv};
2.1.6 비표준 스트링
- c++ 프로그래머 상다수가 c++ 타입 스트링을 잘 사용하지 않는다.
- c++ 규격에 명확히 나오지 않기 때문에 string이라는 타입이 있는 줄도 모르는 이도 있다.
- c++ string을 사용하다가 자신이 원하는 기능이 없거나 인코딩을 무시한다는 사실이 마음에 안들어서
- 가장 큰 이유는 마이크로소프트 MFC의 CString 클래스 처럼 개발 프레임워크나 운영체제에서 나름대로 정의한 스트링을 제공하기 때문
1 C 스트링은 사용하지 않는다
2 MFC나 Qt 등에서 기본적으로 제공하는 스트링처럼 현재 사용하는 프레임워크에서 제공하는 스트링을 프로젝트의 표준 스트링으로 삼는다
3 std::string으로 스트링을 표현한다면 함수의 매개변수로 전달할 읽기 전용 스트링은 std::string_view로 지정한다
2.2 스트링 포맷 지정
auto s1 {format("Read {} bytes from {}", n, "file.txt")};
2.2.1 포맷 지정자
[[fill]align][sign][#][0][width][.precision][type]
1 width
2 [fill]align
2.2.2 포맷 지정자 에러
2.2.3 커스텀 타입 지원
'C++' 카테고리의 다른 글
| [전문가를 위한 C++] 6장 : 재사용을 고려한 설계 (0) | 2026.02.23 |
|---|---|
| [전문가를 위한 C++] 5장 : 객체지향 설계 (0) | 2026.02.23 |
| [전문가를 위한 C++] 4장 : 전문가답게 C++ 프로그램 설계하기 (0) | 2026.02.23 |
| [전문가를 위한 C++] 3장 : 코딩 스타일 (0) | 2026.02.23 |
| [전문가를 위한 C++] 1장 : C++와 표준 라이브러리 초단기 속성 코스 (1) | 2026.02.23 |



