icon
5장 : 배열과 문자열

std::string 클래스

C-스타일 문자열은 수동적인 메모리 관리, 버퍼 오버플로우의 위험, 그리고 불편한 연산자 사용 등 여러 가지 한계를 가지고 있었습니다.

이러한 문제점들을 해결하고 문자열 처리를 훨씬 더 안전하고 효율적이며 편리하게 만들기 위해 C++ 표준 라이브러리에서는 std::string 클래스를 제공합니다.

이 장에서는 std::string이 무엇인지, 어떻게 사용하는지, 그리고 C-스타일 문자열에 비해 어떤 장점을 가지는지 상세히 알아보겠습니다.


std::string 클래스란 무엇인가?

std::string은 C++ 표준 라이브러리(STL: Standard Template Library)의 일부로 제공되는 문자열 전용 클래스입니다.

이 클래스는 문자열 데이터를 객체 지향적인 방식으로 다룰 수 있게 해주며, C-스타일 문자열의 많은 단점을 보완합니다.

주요 특징

  • 동적 크기 조절: std::string은 문자열의 길이에 따라 필요한 만큼 자동으로 메모리를 할당하고 해제합니다. 문자열이 길어지면 메모리를 확장하고, 짧아지면 축소하여 효율적으로 관리합니다. 프로그래머가 직접 메모리 크기를 신경 쓸 필요가 없습니다.
  • 안전한 문자열 처리: 버퍼 오버플로우와 같은 메모리 관련 오류로부터 훨씬 더 안전합니다. 문자열 복사나 이어 붙이기 시에도 자동으로 메모리 크기를 조절하여 안전하게 처리합니다.
  • 직관적인 연산자 오버로딩: C-스타일 문자열에서는 사용할 수 없었던 대입 연산자(=), 비교 연산자(==, !=, <, >), 이어 붙이기 연산자(+, +=) 등을 문자열 객체에 직접 사용할 수 있습니다.
  • 풍부한 멤버 함수: 문자열 길이, 검색, 부분 문자열 추출, 삽입, 삭제 등 다양한 문자열 조작을 위한 편리한 멤버 함수들을 제공합니다.
  • 객체 지향: 문자열을 char 배열이 아닌 하나의 객체로 다루므로, 객체 지향 프로그래밍 패러다임에 더 잘 맞습니다.

std::string 클래스를 사용하려면 프로그램에 <string> 헤더 파일을 포함해야 합니다.

std::string 헤더 포함
#include <string> // std::string을 사용하기 위해 포함

std::string 객체 선언 및 초기화

std::string 객체는 일반 변수를 선언하듯이 선언하고 다양한 방법으로 초기화할 수 있습니다.

1. 기본 생성 (빈 문자열)

빈 문자열로 초기화
#include <string>
#include <iostream>

int main() {
    std::string s1; // 빈 문자열로 초기화 (길이 0)
    std::cout << "s1: " << s1 << std::endl; // 출력: (빈 줄)
    std::cout << "s1의 길이: " << s1.length() << std::endl; // 출력: 0
    return 0;
}

2. 문자열 리터럴로 초기화

문자열 리터럴로 초기화
std::string s2 = "Hello C++"; // 가장 일반적인 방법
std::string s3("Another string"); // 괄호 초기화 (생성자 호출)

3. 다른 std::string 객체로 초기화 (복사 초기화)

복사 초기화
std::string s4 = s2; // s2의 내용을 s4로 복사
std::string s5(s3);  // s3의 내용을 s5로 복사

4. 특정 문자나 문자열의 일부로 초기화

특정 문자나 문자열의 일부로 초기화
std::string s6(5, 'A');      // 'A' 문자 5개로 초기화 -> "AAAAA"
std::string s7(s2, 6, 3);    // s2의 6번 인덱스부터 3개 문자 -> "C++" (s2는 "Hello C++")

std::string의 기본 연산자 사용

std::string은 연산자 오버로딩 덕분에 문자열 처리가 매우 직관적입니다.

1. 대입 연산자 (=): 문자열을 다른 문자열에 할당합니다.

대입 연산자 사용 예시
std::string text = "Initial Text";
text = "New Text Value"; // 기존 문자열 덮어쓰기
std::cout << text << std::endl; // 출력: New Text Value

2. 이어 붙이기 (+, +=): 문자열을 연결합니다 (concatenation).

이어 붙이기 연산자 사용 예시
std::string str_hello = "Hello";
std::string str_world = "World";

std::string full_string = str_hello + " " + str_world + "!"; // + 연산자로 연결
std::cout << full_string << std::endl; // 출력: Hello World!

str_hello += " Everyone!"; // += 연산자로 기존 문자열에 이어 붙이기
std::cout << str_hello << std::endl; // 출력: Hello Everyone!

3. 비교 연산자 (==, !=, <, <=, >, >=): 문자열의 내용을 사전순으로 비교합니다.

비교 연산자 사용 예시
std::string fruit1 = "apple";
std::string fruit2 = "banana";
std::string fruit3 = "apple";

if (fruit1 == fruit3) {
    std::cout << "fruit1과 fruit3는 같습니다." << std::endl; // 실행됨
}
if (fruit1 != fruit2) {
    std::cout << "fruit1과 fruit2는 다릅니다." << std::endl; // 실행됨
}
if (fruit1 < fruit2) { // "apple"이 "banana"보다 사전적으로 앞섬
    std::cout << "fruit1이 fruit2보다 사전적으로 빠릅니다." << std::endl; // 실행됨
}

4. 인덱스 접근 ([], .at()): 특정 위치의 문자에 접근합니다.

인덱스 접근 예시
std::string my_string = "Example";
std::cout << my_string[0] << std::endl; // 'E' (0번 인덱스 문자)
std::cout << my_string[2] << std::endl; // 'a'

my_string[0] = 'e'; // 문자 변경
std::cout << my_string << std::endl; // 출력: example

// .at() 함수: 범위 검사(range check)를 수행하여 안전한 접근 제공
try {
    std::cout << my_string.at(6) << std::endl; // 'e' (유효한 인덱스)
    std::cout << my_string.at(10) << std::endl; // 예외 발생 (std::out_of_range)
} catch (const std::out_of_range& e) {
    std::cerr << "오류: " << e.what() << std::endl;
}
  • [] 연산자는 C-스타일 배열처럼 빠른 접근을 제공하지만, 인덱스 범위를 벗어나도 컴파일 에러를 발생시키지 않고 런타임 오류(예: 크래시)로 이어질 수 있습니다.
  • .at() 멤버 함수는 인덱스 범위를 검사하여, 유효하지 않은 인덱스에 접근하려 할 경우 std::out_of_range 예외를 발생시킵니다. 따라서 더 안전한 접근을 원한다면 .at()을 사용하는 것이 좋습니다.

std::string의 주요 멤버 함수

std::string 클래스는 문자열 조작을 위한 다양한 유용한 멤버 함수들을 제공합니다.

함수명설명예시
.length() 또는 .size()문자열의 길이 (널 문자 제외)를 반환.myString.length()
.empty()문자열이 비어있는지 (길이가 0인지) 확인. true 또는 false 반환.if (myString.empty())
.append(str)문자열 str을 현재 문자열의 끝에 추가. += 연산자와 유사.s.append(" World");
.insert(pos, str)pos 위치에 str을 삽입.s.insert(6, "great ");
.erase(pos, len)pos 위치부터 len 길이만큼 문자열 삭제.s.erase(0, 5); (앞 5개 문자 삭제)
.replace(pos, len, str)pos 위치부터 len 길이만큼을 str로 교체.s.replace(0, 5, "Hi");
.substr(pos, len)pos 위치부터 len 길이만큼의 부분 문자열을 새로 생성하여 반환.std::string sub = s.substr(0, 5);
.find(str, pos)str이 현재 문자열에서 처음 나타나는 인덱스를 pos부터 검색하여 반환. 없으면 std::string::npos 반환.s.find("lo")
.c_str()std::string의 내용을 널 종료된 C-스타일 문자열(const char*)로 반환. (C-스타일 함수와 호환성을 위해)printf("%s", myString.c_str());
.clear()문자열의 모든 내용을 지우고 빈 문자열로 만듦.myString.clear();
std::string 주요 멤버 함수 사용 예시
#include <iostream>
#include <string> // std::string을 위해
#include <cstdio> // printf를 위해 (c_str() 사용 예시)

int main() {
    std::string text = "Programming in C++ is fun.";

    // 길이와 비어있는지 확인
    std::cout << "길이: " << text.length() << std::endl; // 27
    std::cout << "비어있는가? " << std::boolalpha << text.empty() << std::endl; // false

    // 부분 문자열 추출
    std::string sub = text.substr(14, 5); // 14번 인덱스부터 5글자 ("C++ i")
    std::cout << "부분 문자열: " << sub << std::endl; // C++ is

    // 문자열 검색
    size_t pos_cpp = text.find("C++");
    if (pos_cpp != std::string::npos) { // 찾지 못하면 npos 반환
        std::cout << "'C++' 발견 위치: " << pos_cpp << std::endl; // 14
    }

    // 문자열 삽입
    text.insert(10, "with "); // 10번 인덱스에 "with " 삽입
    std::cout << "삽입 후: " << text << std::endl; // Programming with in C++ is fun.

    // 문자열 교체
    text.replace(0, 11, "Coding"); // 0번부터 11글자를 "Coding"으로 교체
    std::cout << "교체 후: " << text << std::endl; // Coding with in C++ is fun.

    // C-스타일 문자열로 변환 (필요 시)
    const char* c_str_ptr = text.c_str();
    printf("C-스타일 문자열로 출력: %s\n", c_str_ptr);

    // 문자열 지우기
    text.clear();
    std::cout << "지운 후 길이: " << text.length() << std::endl; // 0
    std::cout << "지운 후 비어있는가? " << text.empty() << std::endl; // true

    return 0;
}

C-스타일 문자열과 std::string의 변환

  • C-스타일 문자열을 std::string으로: std::string은 C-스타일 문자열 리터럴이나 char* 포인터를 인자로 받는 생성자를 제공하므로, 직접 대입하거나 생성 시 인자로 넘겨주면 됩니다.

    C-스타일 문자열을 std::string으로 변환
    const char* c_str_data = "Hello from C-style!";
    std::string s = c_str_data; // 자동 변환
    std::string s_another(c_str_data); // 생성자 호출
  • std::string을 C-스타일 문자열로: std::string 객체의 내용을 C-스타일 문자열(const char*)로 얻으려면 .c_str() 멤버 함수를 사용합니다. 이 함수는 문자열의 널 종료된 내부 버퍼에 대한 포인터를 반환합니다. 이 포인터는 std::string 객체가 살아있는 동안에만 유효하며, std::string 객체가 변경되거나 소멸되면 무효화될 수 있습니다.

    std::string을 C-스타일 문자열로 변환
    std::string my_cpp_string = "This is C++ string.";
    const char* my_c_string = my_cpp_string.c_str(); // const char*로 변환
    std::cout << my_c_string << std::endl; // 출력: This is C++ string.

결론: std::string 사용의 강력한 권장

C++에서 문자열을 다룰 때는 특별한 C 언어와의 호환성 요구사항이 없는 한, 반드시 std::string 클래스를 사용하는 것이 좋습니다.

std::string은 C-스타일 문자열이 가진 모든 단점을 보완하고, 훨씬 더 안전하고 편리하며 효율적인 문자열 처리 기능을 제공합니다.

현대 C++ 프로그래밍에서 std::string은 문자열을 다루는 표준이자 최선의 방법입니다.