[C++] 문자열 클래스 만들기

chxxrin·2024년 7월 25일
0

C++

목록 보기
15/22

코드 설명 : 문자열을 다루기 위한 MyString 클래스를 정의하고 사용하는 방법

MyString 클래스 정의

  1. 멤버 변수:
  • int size_: 문자열의 길이를 저장합니다.
  • char *str_: 동적으로 할당된 문자열을 가리키는 포인터입니다.
  1. 생성자:
  • 기본 생성자 MyString(): 문자열의 기본 크기를 1로 설정하고, 메모리를 동적으로 할당합니다.
MyString()
{
    cout << "MyString()" << endl;
    size_ = 1;
    str_ = new char[size_];
}
  • 초기화 생성자 MyString(const char *init_str): 문자열을 인자로 받아 초기화합니다. 문자열의 길이를 계산하고, 동적으로 메모리를 할당하여 문자열을 복사합니다.
    - init_str이 유효한 메모리라고 가정
    • 생성자에서는 널포인트를 제외한 글자수를 세고있음
MyString(const char *init_str)
{
    cout << "MyString(const char *init_str)" << endl;
    
    // 1. 글자 수 먼저 확인
    size_ = 0; // 글자수를 size에 저장
    while (init_str[size_] != '\0')
    {
        size_++;
    }
    
    // 2. 글자 수가 0이 아니면 메모리 할당
    if (size_ > 0)
    {
        str_ = new char[size_]; // 동적할당으로 딱 받을만큼만 받고있음
    }
    
    // 3. 복사 (글자 개수만큼만 복사, 사이즈를 알고있기 때문에 널캐릭터를 복사하지 않아도된다)
    for (int i = 0; i < size_; i++)
    {
        str_[i] = init_str[i];
    }
    // memcpy() 사용 가능
}
  1. 소멸자:
  • ~MyString(): 객체가 소멸될 때 호출되며, 동적으로 할당된 메모리를 해제합니다.
    - 변수들이 메모리에 공간을 차지하지 못하고 사라질 때 알아서 호출됨
    • 끝나기 전에 메모리 반납하는 역할
~MyString()
{
    cout << "Destructor" << endl;
    size_ = 0;
    
    // 만약 동적할당 받은 메모리가 있다면, 메모리가 0이 아니라면 메모리를 반납!
    if (str_)
        delete[] str_;
}
  1. 멤버 함수:
  • void Resize(int new_size): 문자열의 크기를 변경합니다. 새 크기만큼 메모리를 재할당하고, 기존 데이터를 복사합니다.
void Resize(int new_size) // 새로운 사이즈가 입력으로 들어오면
{
    char *new_str = new char[new_size]; // 새로 할당을 받고
    
    // memcpy() 사용 가능 // 원래갖고있던 데이터를 복사하고 
    for (int i = 0; i < (new_size < size_ ? new_size : size_); i++)
    {
        new_str[i] = str_[i];
    }
    
    // 기존 데이터를 삭제
    delete[] str_;
    str_ = new_str;
    size_ = new_size;
}
  • void Print(): 문자열을 출력합니다.
void Print()
{
    for (int i = 0; i < size_; i++)
    {
        cout << str_[i]; 
        // 한글자한글자 일일히 출력해야함. 마지막에 널 캐릭터가 항상 들어있다는 보장이 없기 때문에 
    }
    cout << endl;
}
  • void Append(MyString *app_str): 다른 MyString 객체의 문자열을 현재 객체의 문자열에 추가합니다. 먼저 현재 문자열의 크기를 늘린 다음, 추가할 문자열을 복사합니다.
void Append(MyString *app_str)
{
    int old_size = size_; // 원래 몇글자였는지 기억하기 위해 임시로 사이즈를 저장해놓음
    Resize(size_ + app_str->size_); // 다른 멤버 함수 호출 가능
    for (int i = old_size; i < size_; i++)
    {
        cout << i << " " << i - old_size << endl;
        str_[i] = app_str->str_[i - old_size];
    }
}

main 함수

  1. 객체 생성 및 초기화:
  • MyString str1("ABCDE");: "ABCDE"로 초기화된 str1 객체를 생성합니다.
  • MyString str2("123");: "123"로 초기화된 str2 객체를 생성합니다.
MyString str1("ABCDE");
MyString str2("123");
  1. 문자열 출력:
  • str1.Print();: str1의 문자열을 출력합니다.
str1.Print();
  1. 문자열 추가:
  • str1.Append(&str2);: str1에 str2의 문자열을 추가합니다.
str1.Append(&str2);

전체코드

/*
    홍정모 연구소 https://honglab.co.kr/
*/

#include <iostream>
#include <cstring>

using namespace std;

// public, private 접근 권한 안내

class MyString
{
public:
    MyString()
    {
        // 호출 시점 확인
        cout << "MyString()" << endl;

        size_ = 1;
        str_ = new char[size_];
    }

    MyString(const char *init_str) // init_str이 유효한 메모리라고 가정, 생성자에서는 널포인트를 제외한 글자수를 세고있음
    {
        cout << "MyString(const char *init_str)" << endl;

        // 1. 글자 수 먼저 확인
        size_ = 0; // 글자수를 size에 저장
        while (init_str[size_] != '\0')
        {
            size_++; // ++ 연산자 안내
        }

        // 2. 글자 수가 0이 아니면 메모리 할당
        if (size_ > 0)
        {
            str_ = new char[size_]; // 동적할당으로 딱 받을만큼만 받고있음
        }

        // 3. 복사 (글자 개수만큼만 복사, 사이즈를 알고있기 때문에 널캐릭터를 복사하지 않아도된다)
        for (int i = 0; i < size_; i++)
        {
            str_[i] = init_str[i];
        }
        // memcpy() 사용 가능
    }

    ~MyString() // 소멸자(변수들이 메모리에 공간을 차지하지 못하고 사라질 때 알아서 호출됨, 끝나기 전에 메모리 반납하는 역할)
    {
        // 호출 시점 확인
        cout << "Destructor" << endl;

        size_ = 0;
        if (str_) // 만약 동적할당 받은 메모리가 있다면, 메모리가 0이 아니라면 메모리를 반납!
            delete[] str_;
    }

    void Resize(int new_size) // 새로운 사이즈가 입력으로 들어오면
    {
        char *new_str = new char[new_size]; // 새로 할당을 받고

        // memcpy() 사용 가능 // 원래갖고있던 데이터를 복사하고 
        for (int i = 0; i < (new_size < size_ ? new_size : size_); i++)
        {
            new_str[i] = str_[i];
        }

        // 기존 데이터를 삭제
        delete[] str_;
        str_ = new_str;
        size_ = new_size;

        // new_str 지우면 안되요!
    }

    void Print()
    {
        for (int i = 0; i < size_; i++)
        {
            cout << str_[i]; // 한글자한글자 일일히 출력해야함. 마지막에 널 캐릭터가 항상 들어있다는 보장이 없기 때문에 
        }
        cout << endl;
    }

    void Append(MyString *app_str) // 같은 타입을 매개변수로 사용 가능
    {
        int old_size = size_; // 원래 몇글자였는지 기억하기 위해 임시로 사이즈를 저장해놓음

        // 다른 멤버 함수 호출 가능
        Resize(size_ + app_str->size_);

        // 중요한 개념
        for (int i = old_size; i < size_; i++)
        {
            cout << i << " " << i - old_size << endl;
            str_[i] = app_str->str_[i - old_size];
        }
    }

private:
    int size_ = 0;        // m_size
    char *str_ = nullptr; // m_str (여기서는 구글 스타일)
};

int main()
{
    // 클래스 기본 문법 안내

    MyString str1("ABCDE"); // 생성자 이용
    MyString str2("123");

    str1.Print();

    str1.Append(&str2); // 주소 넣어줌

    str1.Print();

    str1.Append(&str2);

    str1.Print();

    MyString str3("Hello, World!");

    str3.Append(&str1);
    str3.Print();

    return 0;
}

출력 결과

MyString(const char *init_str)
MyString(const char *init_str)
ABCDE
5 0
6 1
7 2
ABCDE123
8 0
9 1
10 2
ABCDE123123
MyString(const char *init_str)
13 0
14 1
15 2
16 3
17 4
18 5
19 6
20 7
21 8
22 9
23 10
Hello, World!ABCDE123123
Destructor
Destructor
Destructor

출처 : 홍정모 유튜브

0개의 댓글

관련 채용 정보