문자열 클래스
c언어에서는 문자열을 나타내기 위해 문자열 끝에 NULL 문자를 붙여서 문자열을 나타내는 방식을 사용했다.
그러나 만들어진 문자열의 크기를 바꾸거나 문자열 뒤에 다른 문자열을 붙이는 작업이 매우 번거로웠다.
이 작업을 문자열 클래스를 만들어서 지원해주면 편할 것이다.
c++에서는 char 배열을 사용하는 것보다 string으로 문자열을 다루는게 좋다. string으로 문자열 다룰 때 #include <string.h> 잊어서는 안되구..
직접 Mystring이라는 문자열 클래스를 만들어보자. 필요한 데이터는
1. 문자열 데이터가 저장된 공간을 가리키는 포인터
2. 문자열 데이터 길이
데이터를 그대로 보관하지 않고 1로 하는 이유는 문자열 데이터 크기가 바뀔 때 저장된 공간을 가리키는 방식으로 하면 메모리를 해제하고 다시 할당할 수 있기 때문이다.
2를 보관하는 이유는 문자열 길이를 사용할 일이 많은데 굳이 계속 구하는 것은 불편하니까 그냥 보관을 하는것이다.
이렇게 구성해주기!
갑자기 화질이 좋아졌쬬? 노트북 바꿨거든요 헤헤(자랑하기)
아무튼간에 함수들은 주석을 참고해주시고 ~string은 new로 동적할당한 것들을 해제하는 함수
length는 길이를 리턴하는 함수
print는 문자열을 출력하는 함수이다.
이제 함수를 하나씩 정의해보아요! 주석 보고, 코드는 쉽게 이해될 것이예요!
다만 여기서 new로 새로 할당을 해줬다는 점은 알아두자
나머지도 주석 보면 다 이해가 될 정도이다.
hello world!를 str1에 저장하고 str1을 str2에 저장한다.
그리고 두개를 프린트하면?
이렇게 hello world!가 출력된다.
assign 함수
assign함수는 우리가 흔히 생각하는 =와 동일한 역할이다.
위 코드에서 mystring 클래스가 있고 변수 str을 정의했다고 치면 그러니까
mystring str("hi!");
이런식으로
그리고 str.assign("abc");
이렇게 하면 str에 원래 있던 hi는 지워지고 abc가 들어간다.
assign 함수는 두가지로 나눠서 준비해두자.
MyString& assign(const MyString& str);
MyString& assign(const char* str);
그러면 코드가 이렇게 작성된다. 코드는 주석을 참고해서 읽으면 이해된다.
MyString& MyString::assign(const MyString& str) {
if (str.string_length > string_length) {
// 그러면 다시 할당을 해줘야만 한다.
delete[] string_content;
string_content = new char[str.string_length];
}
for (int i = 0; i != str.string_length; i++) {
string_content[i] = str.string_content[i];
}
// 그리고 굳이 str.string_length + 1 ~ string_length 부분은 초기화
// 시킬 필요는 없다. 왜냐하면 거기 까지는 읽어들이지 않기 때문이다.
string_length = str.string_length;
return *this;
}
MyString& MyString::assign(const char* str) {
int str_length = strlen(str);
if (str_length > string_length) {
// 그러면 다시 할당을 해줘야만 한다.
delete[] string_content;
string_content = new char[str_length];
}
for (int i = 0; i != str_length; i++) {
string_content[i] = str[i];
}
string_length = str_length;
return *this;
}
입력받는 문자열의 크기가 원래 문자열의 크기보다 작으면 굳이 동적할당을 다시 할 필요가 없다. 그냥 새로 문자를 하나씩 넣어주면 되기 때문이다.
그러나 문제가 발생할 수도 있는데
맨 처음에 str에 아주아주아주아주 긴 문자열을 할당했다고 하자. 문자열의 길이가 1000바이트가 될 정도로
그다음에 짧은 문자열을 assign했다고 하자.
위에 검정색 밑줄 코드에 의하면 긴 문자가 할당되어 있는 상태에서 더 짧은 문자열을 assign하면 동적할당 없이 string_length 값이 작아지고 짧은 문자열로 덮어씌워진다.
문제는 str1에 다시 긴 문자열을 assign했을 때이다. 한 998바이트짜리 문자열 길이라고 생각해보자.
그러면 비록 str1에는 1000바이트의 공간이 할당되어 있는데도 현재 문자열 길이는 짧으니까 이전의 1000바이트 공간이 있다는 사실을 모르고 새로 많은 양의 메모리를 할당하게 된다.
이것은 매우매우 비효율적이다.
그래서 얼마나 공간이 할당되어 있는지 알 수 있도록 따로 memory_capacity라는 변수를 추가한다.
MyString& MyString::assign(const MyString& str) {
if (str.string_length > memory_capacity) {
// 그러면 다시 할당을 해줘야만 한다.
delete[] string_content;
string_content = new char[str.string_length];
memory_capacity = str.string_length;
}
for (int i = 0; i != str.string_length; i++) {
string_content[i] = str.string_content[i];
}
// 그리고 굳이 str.string_length + 1 ~ string_length 부분은 초기화
// 시킬 필요는 없다. 왜냐하면 거기 까지는 읽어들이지 않기 때문이다.
string_length = str.string_length;
return *this;
}
MyString& MyString::assign(const char* str) {
int str_length = strlen(str);
if (str_length > memory_capacity) {
// 그러면 다시 할당을 해줘야만 한다.
delete[] string_content;
string_content = new char[str_length];
memory_capacity = str_length;
}
for (int i = 0; i != str_length; i++) {
string_content[i] = str[i];
}
string_length = str_length;
return *this;
}
이렇게! memory_capacity 변수가 무엇인지 알면 아까랑 거의 비슷한 것이니 이해할 수 있다.
insert 문자 삽입
문자를 삽입하기 위해서 필요한 함수들이다. 주석을 참고하면 대충 함수가 어떻게 쓰이는지는 알 수 있다.
너무너무 길어서 소스파일을 올려두었당..
앞쪽에서도 얘기했지만 씹어먹는 C++ - <4 - 5. 내가 만드는 String 클래스> (modoocode.com)
씹어먹는 C++ - <4 - 5. 내가 만드는 String 클래스>
modoocode.com
모두의 코드님 글들을 참고삼아서 글을 작성하고 있는 거라서 여기서 보면 더 친절한(?) 설명을 볼 수 있다.
본인은 주석을 보면서 이해를 마친 상태!
여기서 새로 메모리를 할당할 경우, 아닌 경우를 나누어서 처리가 되는데
원래 문자열 길이+새로 삽입할 문자열 길이 > 현재 할당된 메모리 크기
이러면 메모리를 반드시 새로 할당해야 한다.
하지만 작다면 굳이 해제하고 재할당할 필요 없다.
그런데 예를 들어서 100바이트 용량을 가진 문자열에 100바이트만큼 문자열이 할당되어있다고 해보자
그런데 계속 문자 하나씩만 넣는 작업을 반복한다고 하면
100바이트 해제하고 101바이트 할당
101바이트 해제하고 102바이트 할당
...
이런식으로 진행될텐데 작업 낭비가 심하다.
그러면 하나 추가할때 혹시모르니까 1000바이트 더 할당해놔야겠다!
이러기도 좀 그런게 자원 낭비가 심하니까..
그래서 두가지 문제를 모두 해결할 수 있는 방법으로 메모리를 할당할 때 현재 메모리 크기의 2배를 할당해 놓는 방법이 있다.
erase 지우는 함수
지우는 것은 데이터 크기를 생각할 필요 없이 그냥 하나 지우면 되니까 훨씬 쉽다.
mystring& erase(int loc, int num); 함수를 이렇게 정의하면 된다.
예를 들어 hello가 있는데 erase(1,2); 하면 hlo가 리턴된다. 1에 해당하는 문자부터 2개 없앤다고 생각하면 됨!
string_length가 있다보니 지우는 문자 개수만큼 string_length값에서 빼면 알아서 프린트도 하고~ 삽입도 하고~ 여기저기 쓰일 곳이 많으니까 편리하다.
find 함수
find 함수는 구현하는 방식에 따라 클래스 성능이 좌우되기 때문에 효율적으로 구성하는 것이 중요하다.
이렇게 함수를 정의하고 find 함수는 find_from에서부터 가장 첫번째 str위치를 리턴한다.
포함이 안되면 -1을 리턴하는 것이다.
알고리즘을 대략 이해해보면 문자열 길이가 0이면 그냥 못찾은거니까 -1 리턴하고
반복문 돌려서 find_from부터 문자열 끝까지 하나씩 더해가면서 돌리고
동시에 0부터 문자열 길이까지 돌리고
이중 for문 써가지고 만약에 i+j의 내용과 str의 i+j의 내용이 같지 않으면 나가고,
초록 반복문은 계속 돌아가는 상태에서 j와 str의 문자열 길이가 같으면 i를 반환하면 된다.
i를 출력한다는 것은 몇번째에 그 문자가 있다는 것인지 알려준다는것!
i를 반환하지 못했다는 것은 결국
이 문자열의 길이는 0개 초과인데도 찾고있는 문자열이 문자열 안에 없다는 것을 의미하니까
-1을 반환하면 된다.
코드가 너무 길어성..
씹어먹는 C++ - <4 - 5. 내가 만드는 String 클래스> (modoocode.com)
씹어먹는 C++ - <4 - 5. 내가 만드는 String 클래스>
modoocode.com
여기를 참고해주세요 ㅎㅎ
우리가 c언어에서 많이 하는 strcmp함수같은 것도 compare함수를 만들어서 사용해줘야하는데..
저 너무 힘들어요 살려주세요
코드를 보면 이해할 정도이니 잘 보고 공부해봐용:-)
'CODING > C++ STUDY' 카테고리의 다른 글
C++ 독학 9일차 - 오버로딩 (0) | 2021.07.29 |
---|---|
C++ 독학 8일차 - explicit, mutable (0) | 2021.07.29 |
C++ 독학 7일차 - 디폴트 복사 생성자, 생성자 초기화 리스트, const, static, this 포인터 (0) | 2021.07.28 |
C++ 독학 6일차(7/24) - 소멸자, 복사생성자 (0) | 2021.07.26 |
C++ 독학 5일차 - 객체 지향 프로그래밍, 함수의 오버로딩 (0) | 2021.07.23 |