문자열 클래스 만들기
class 문법에 익숙해지고, 문자열을 더 잘 다루기 위해 문자열 클래스를 직접 만들어보았다.
cstring의 문자열, 즉 배열을 사용하여 string class를 만든다.
c++에서 #include <string>을 사용하면 같은 메서드를 사용할 수 있다.
클래스 전체 틀
Public에 사용할 함수들을 정의하고
Private은
문자열을 저장할 배열 str_을 선언
문자열 크기를 저장할 size_ 선언
#include <iostream>
#include <algorithm> // swap
#include <cassert>
class MyString
{
public:
MyString(); // 비어 있는 MyString() 생성
MyString(const char* init); // 맨 뒤에 널 캐릭터'\0'가 들어 있는 문자열로부터 초기화
MyString(const MyString& str); // MyString의 다른 instance로부터 초기화
~MyString();
bool IsEmpty();
bool IsEqual(const MyString& str);
int Length();
void Resize(int new_size);
MyString Substr(int start, int num); // 인덱스 start위치의 글자부터 num개의 글자로 새로운 문자열 만들기
MyString Concat(MyString app_str); // 뒤에 덧붙인 새로운 문자열 반환 (append)
MyString Insert(MyString t, int start); // 중간에 삽입
int Find(MyString pat);
void Print();
private:
char* str_ = nullptr; // 마지막에 '\0' 없음
int size_ = 0; // 글자 수
};
생성자 & 소멸자
MyString의 생성자는 3가지로 만들었다.
1. default 생성자 : 비어있는 MyString 생성
2. cstring의 문자열 생성자 : 맨 뒤에 널 캐릭터'\0'가 들어 있는 문자열로부터 초기화
3. MyString으로 선언된 문자열로 초기화 : 복사 생성자
MyString의 소멸자는 str_의 메모리 공간을 반납한다.
배열을 메모리공간을 반납할 때는 delete []를 사용해야 한다. <-> 그냥 delete와 다름
MyString()
{
str_ = nullptr;
size_ = 0;
}
MyString(const char* init)
{
// init의 문자열 크기를 구한다.
for(int i =0; init[i] != '\0';i++)
size_++;
// 크기만큼 str_에 메모리 할당
str_ = new char[size_];
// 공간을 만든 str_에 size_크기 만큼 값 복사
memcpy(str_, init, size_);
}
MyString(const MyString& str)
{
str_ = new char[str.size_];
size_ = str.size_;
memcpy(str_, str.str_, str.size_);
}
~MyString()
{
if(str_ != nullptr) //비어있지 않다면 -> 할당되어있다면
delete[] str_;
}
IsEmpty()
문자열이 비었는지 확인
bool IsEmpty()
{
return Length() == 0;
}
IsEqual()
1. 길이가 다르다면 바로 false
2. 선형탐색 -> 값이 다르면 바로 false
3. 위 두 조건이 아니라면 true
bool IsEqual(const MyString& str)
{
if (this->size_ != str.size_)
return false;
for (int i = 0; i < this -> size_; i++)
{
if (str_[i] != str.str_[i])
return false;
}
return true;
}
Length()
문자열 길이 구해주는 함수
size_ 반환하면 끝난다.
int Length()
{
return size_;
}
Resize()
문자열의 메모리 공간을 새로 할당해주는 함수
원래 내용을 복사하는데 새로운공간이 작다면 그만큼만 복사함
크다면 전부다 복사한다
void Resize(int new_size)
{
if (new_size != 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_ 버리고
str_ = new_str; // Resize한 새로운 str_ 만든다.
size_ = new_size;
}
}
}
Substr()
기존의 문자열에서 부분적으로 떼서 새로운 문자열 만드는 함수
- 뗄 문자열의 시작인덱스와 그 위치부터 몇 문자를 뗄지를 매개변수로 받는다.
빈 문자열을 만들고 Resize를 통해 메모리 공간을 할당할 수도 있다.
MyString Substr(int start, int num)
{
MyString temp;
temp.size_ = num;
char* temp = new char[temp.size_];
//temp.Resize(num);도 가능
for (int i = 0; i < temp.size_; i++)
{
temp.str_[i] = str_[start + i]; //str_는 this -> str_ 으로도 표현가능
}
return temp;
}
Concat()
기존의 문자열에 추가시킬 문자열을 덧붙인다.
참조를 활용하며 배열의 중간 위치에 접근할수 있다.
MyString Concat(MyString app_str)
{
MyString temp;
temp.size_ = size_ + app_str.size_;
temp.Resize(temp.size_);
memcpy(temp.str_, str_, size_);
memcpy(&temp.str_[size_], app_str, app_str.size_);
return temp
}
Insert()
특정 문자열을 기존 문자열의 특정인덱스 에 삽입하여 하나의 문자열을 만드는 함수
1. temp문자열에 삽입 전까지 그대로 복사
2. temp 문자열에 이어서 t문자열 붙임
3. temp 문자열에 이어서 남은 str_붙임
MyString Insert(MyString t, int start)
{
assert(start >= 0);
assert(start <= this->size_); //삽입 불가능한 인덱스라면 assert처리
MyString temp;
temp.size_ = size_ + t.size_;
temp.Resize(temp.size_);
memcpy(temp.str_, str_, start)
for(int i = start; i < start + t.size_; i++)
{
temp[i] = t[i-start];
}
for(int i = start + t.size_; i < temp.size_; i++)
{
temp[i] = str_[i - t.size_];
}
return temp;
}
Find()
문자열 안에서 특정 문자열을 찾아내는 함수
int Find(MyString pat)
{
for (int i = 0; i < size_ - pat.size_; i++)
{
for (int j = 0; j < pat.size_; j++)
{
if (str_[i + j] != pat.str_[j])
break;
if (j == pat.Length() - 1) //문제없이 다 검색되었다면
return i; //i값 즉 시작인덱스 값을 반환한다.
}
}
return -1;
}
📂 전체코드
#include <iostream>
#include <algorithm> // swap
#include <cassert>
class MyString
{
public:
MyString()
{
str_ = nullptr;
size_ = 0;
}
MyString(const char* init)
{
// init의 문자열 크기를 구한다.
for (int i = 0; init[i] != '\0'; i++)
size_++;
// 크기만큼 str_에 메모리 할당
str_ = new char[size_];
// 공간을 만든 str_에 size_크기 만큼 값 복사
memcpy(str_, init, size_);
}
MyString(const MyString& str)
{
str_ = new char[str.size_];
size_ = str.size_;
memcpy(str_, str.str_, str.size_);
}
~MyString()
{
if (str_ != nullptr) //비어있지 않다면 -> 할당되어있다면
delete[] str_;
}
bool MyString::IsEmpty()
{
return Length() == 0;
}
bool IsEqual(const MyString& str)
{
if (this->size_ != str.size_)
return false;
for (int i = 0; i < this->size_; i++)
{
if (str_[i] != str.str_[i])
return false;
}
return true;
}
int Length()
{
return size_;
}
void Resize(int new_size)
{
if (new_size != 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_ 버리고
str_ = new_str; // Resize한 새로운 str_ 만든다.
size_ = new_size;
}
}
MyString Substr(int start, int num)
{
MyString temp;
temp.size_ = num;
char* temp = new char[temp.size_];
//temp.Resize(num);도 가능
for (int i = 0; i < temp.size_; i++)
{
temp.str_[i] = str_[start + i]; //str_는 this -> str_ 으로도 표현가능
}
return temp;
}
MyString Concat(MyString app_str)
{
MyString temp;
temp.size_ = size_ + app_str.size_;
temp.Resize(temp.size_);
memcpy(temp.str_, str_, size_);
memcpy(&temp.str_[size_], app_str, app_str.size_);
return temp
}
MyString Insert(MyString t, int start)
{
assert(start >= 0);
assert(start <= this->size_); //삽입 불가능한 인덱스라면 assert처리
MyString temp;
temp.size_ = size_ + t.size_;
temp.Resize(temp.size_);
memcpy(temp.str_, str_, start)
for (int i = start; i < start + t.size_; i++)
{
temp[i] = t[i - start];
}
for (int i = start + t.size_; i < temp.size_; i++)
{
temp[i] = str_[i - t.size_];
}
return temp;
}
int Find(MyString pat)
{
for (int i = 0; i < size_ - pat.size_; i++)
{
for (int j = 0; j < pat.size_; j++)
{
if (str_[i + j] != pat.str_[j])
break;
if (j == pat.Length() - 1) //문제없이 다 검색되었다면
return i; //i값 즉 시작인덱스 값을 반환한다.
}
}
return -1;
}
void Print()
{
for (int i = 0; i < size_; i++)
cout << str_[i];
cout << endl;
}
}
private:
char* str_ = nullptr; // 마지막에 '\0' 없음
int size_ = 0; // 글자 수
};
'💻 Computer Science > Data structure' 카테고리의 다른 글
[자료구조] 큐(Queue) 개념, 원형 큐로 직접 구현해보기 C++ (0) | 2024.05.12 |
---|---|
[자료구조] 스택(Stack) 개념, 동적배열로 스택 직접 구현하기 C++ (0) | 2024.05.10 |