티스토리 뷰
주의 사항!
- 이 글은 제가 직접 공부하는 중에 작성되고 있습니다.
- 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
- 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.
이번 절에서는 C언어에서 사용하는 문자열과 C++에서 제공하는 std::string 클래스의 장단점을 알아보고, char 타입의 배열이나 포인터를 사용하는 것에 대해 비교 설명하고자 합니다.
C언어에서는 문자열을 표기할 때 다음과 같이 char 타입을 사용합니다.
#pragma warning(disable: 4996)
#include <iostream>
#include <cstring>
#include <cstdlib>
int main()
{
const char* cc = "문자열을 입력합니다. this is a string";
char cb[17];
char* str;
memcpy(cb, cc, 17);
str = (char*)malloc(strlen(cc) + 1);
strcpy(str, cc);
//'\0'이 없기 때문에 변수의 크기를 넘어 일부 데이터가 깨지는 에러 발생
std::cout << "cc = " << cc << ", 문자열의 크기는 " << strlen(cc) << std::endl;
std::cout << "cb = " << cb << ", 문자열의 크기는 " << strlen(cb) << std::endl;
std::cout << "str = " << str << ", 문자열의 크기는 " << strlen(str) << std::endl;
free(str);
}
/*
실행 결과
cc = 문자열을 입력합니다. this is a string, 문자열의 크기는 37
cb = 문자열을 입력합니儆儆儆儆儆??, 문자열의 크기는 31
str = 문자열을 입력합니다. this is a string, 문자열의 크기는 37
*/
C언어에서 문자열을 다룰 때는 char 타입의 배열을 사용하거나 또는 문자열의 크기를 알아서 malloc() 함수를 사용하여 메모리 공간을 할당받아 사용해왔습니다. 그리고 경계 검사를 하랴 문자열 끝에 '\0'을 삽입하랴 여간 까다로운 것이 아님을 알았을 것입니다.
위와 같은 문제를 해결할 수 있는 가장 쉬운 방법은 아래와 같이 std::string 클래스를 사용하는 것입니다. 해당 클래스는 string 헤더 파일에 선언되어 있습니다.
#include <iostream>
#include <string>
int main()
{
const char* cc = "문자열을 입력합니다. This is a string";
std::string str;
str = cc;
std::cout << "str = " << str.data() << ", 문자열의 크기는 " << str.length() << std::endl;
str = "클래스 내부에서 공간을 잡는다.";
str += " 따라서 별도 메모리 공간을 잡지 않아도 사용이 가능하다.";
std::cout << "str = " << str.data() << "문자열의 크기는 " << str.length() << std::endl;
}
/*
실행 결과
str = 문자열을 입력합니다. This is a string, 문자열의 크기는 37
str = 클래스 내부에서 공간을 잡는다. 따라서 별도 메모리 공간을 잡지 않아도 사용이 가능하다.문자열의 크기는 85
*/
참고로 printf는 C언어에서 사용하는 함수이므로 std::string 타입의 변수를 그대로 사용하면 제대로 변환하지 못합니다. 그리고 std::string 타입을 사용하면 다음과 같이 문자열을 선언할 수 있으므로 문자열에 대한 고민을 상당수 덜어낼 수 있습니다.
#include <iostream>
#include <string>
int main()
{
std::string str1("Initial string");
std::string str2;
//str1 변수의 문자열을 복사하여 str3 변수에 대입
std::string str3(str1);
//str1 변수에 저장된 문자열의 9번째 문자부터 시작해 3개의 문자를 복사하여 대입
std::string str4(str1, 8, 3);
//str1 변수에 저장된 문자열의 7번째 문자부터 마지막 문자까지 복사하여 대입
std::string str5(str1, 6);
//str6 변수에 'x' 문자를 10개 반복하여 입력, 숫자가 나온 다음 문자가 나오면 문자의 반복을 의미
std::string str6(10, 'x');
std::cout << "str1 : " << str1.data() << std::endl;
std::cout << "str2 : " << str2.data() << std::endl;
std::cout << "str3 : " << str3.data() << std::endl;
std::cout << "str4 : " << str4.data() << std::endl;
std::cout << "str5 : " << str5.data() << std::endl;
std::cout << "str6 : " << str6.data() << std::endl;
return 0;
}
/*
실행 결과
str1 : Initial string
str2 :
str3 : Initial string
str4 : str
str5 : l string
str6 : xxxxxxxxxx
*/
std::string 클래스 흉내 내기
연산자 오버 로딩에 대해서 어느 정도 알고 있다면 std::string 클래스를 흉내 내는 mystring 클래스를 한 번 만들어 보길 권합니다. string 클래스를 모델로 삼아서 연산자가 어떠한 형태로 오버 로딩되어 있는지 고민해 보고, 이와 유사한 문자열 처리 클래스를 직접 구현해보는 것은 표준 std::string 클래스를 사용하는 것 이상의 의미가 있습니다.
우선 string 클래스의 사용 예제를 먼저 보겠습니다.
//main.cpp 소스 파일로 저장
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string str1 = "I like ";
string str2 = "string class";
string str3 = str1 + str2;
cout << str1 << endl;
cout << str2 << endl;
cout << str3 << endl;
str1 += str2;
if (str1 == str3)
{
cout << "동일 문자열!" << endl;
}
else
{
cout << "동일하지 않은 문자열!" << endl;
}
string str4;
cout << "문자열 입력 : ";
cin >> str4;
cout << "입력한 문자열 : " << str4 << endl;
return 0;
}
/*
실행결과
I like
string class
I like string class
동일 문자열!
문자열 입력 : hello
입력한 문자열 : hello
*/
그리고 위 예제를 그대로 구현할 수 있는 mystring 클래스를 정의해보기 바랍니다. 실제 string 클래스는 위 예제에서 보여주는 것 이상의 기능을 가지고 있습니다. 그러나 우리의 목적은 이와 유사한 성격의 클래스를 직접 정의하는 것이므로, 이 정도로 마무리하고자 합니다.
('더 보기'를 클릭하면 제가 구현한 mystring 클래스를 볼 수 있습니다.)
//mystring.h 헤더 파일로 저장
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
using namespace std;
class MyString
{
private:
char* str;
public:
MyString();
MyString(const char* str);
MyString(const MyString& ref);
MyString& operator=(const MyString& ref);
MyString operator+(const MyString& ref);
MyString& operator+=(const MyString& ref);
bool operator==(const MyString& ref);
~MyString();
friend ostream& operator<<(ostream& os, const MyString& ref);
friend istream& operator>>(istream& is, MyString& ref);
};
#endif
#include "myString.h"
#include <cstring>
MyString::MyString()
{
str = NULL;
}
MyString::MyString(const char* str)
{
this->str = new char[strlen(str) + 1];
strcpy(this->str, str);
}
MyString::MyString(const MyString& ref)
{
str = new char[strlen(ref.str) + 1];
strcpy(str, ref.str);
}
MyString& MyString::operator=(const MyString& ref)
{
if (str != NULL) delete[] str;
str = new char[strlen(ref.str) + 1];
strcpy(str, ref.str);
return *this;
}
MyString MyString::operator+(const MyString& ref)
{
int len = strlen(str) + strlen(ref.str) + 1;
char* mystr = new char[len];
strcpy(mystr, str);
strcat(mystr, ref.str);
MyString string(mystr);
delete[] mystr;
return string;
}
MyString& MyString::operator+=(const MyString& ref)
{
if (str != NULL)
{
char* mystr = new char[strlen(str) + strlen(ref.str) + 1];
strcpy(mystr, str);
delete[] str;
strcat(mystr, ref.str);
str = new char[strlen(mystr) + 1];
strcpy(str, mystr);
delete[] mystr;
}
else
{
str = new char[strlen(ref.str) + 1];
strcpy(str, ref.str);
}
return *this;
}
bool MyString::operator==(const MyString& ref)
{
return (strcmp(str, ref.str) == 0) ? true : false;
}
MyString::~MyString()
{
delete[] str;
}
ostream& operator<<(ostream& os, const MyString& ref)
{
os << ref.str;
return os;
}
istream& operator>>(istream& is, MyString& ref)
{
char simpleStr[200];
is >> simpleStr;
if (ref.str != NULL)
{
delete[] ref.str;
}
ref.str = new char[strlen(simpleStr) + 1];
strcpy(ref.str, simpleStr);
return is;
}
//main.cpp 소스 파일로 저장
#include <iostream>
#include "myString.h" //직접 정의한 string클래스
using namespace std;
int main(void)
{
MyString str1 = "I like "; //직접 정의한 string 클래스로 객체 생성
MyString str2 = "string class";
MyString str3 = str1 + str2;
cout << str1 << endl;
cout << str2 << endl;
cout << str3 << endl;
str1 += str2;
if (str1 == str3)
{
cout << "동일 문자열!" << endl;
}
else
{
cout << "동일하지 않은 문자열!" << endl;
}
MyString str4;
cout << "문자열 입력 : ";
cin >> str4;
cout << "입력한 문자열 : " << str4 << endl;
return 0;
}
/*
실행결과
I like
string class
I like string class
동일 문자열!
문자열 입력 : Hello
입력한 문자열 : Hello
*/
'공부 일지 > CPP 공부 일지' 카테고리의 다른 글
C++ | 예외상황과 예외처리 (0) | 2021.08.05 |
---|---|
C++ | 템플릿(template) (0) | 2021.08.05 |
C++ | 그 외의 연산자 오버로딩(스마트 포인터, 펑터) (1) | 2021.08.03 |
C++ | 연산자 오버로딩 (0) | 2021.08.03 |
C++ | 다중 상속(Multiple Inheritance) (0) | 2021.08.03 |