C++ STRCAT 구현부분 질문
조회수 250회
include
using namespace std;
class My_string
{
private:
char* str;
public:
My_string(char *a) { str = a; };
~My_string() { };
int my_strlen() {
int b = 0;
while (1) {
if (str[b] == NULL)
{
break;
}
b++;
}
return b;
};
void my_strcpy(char* a) {
str = a;
};
void my_strcat(char* a) {
char* idx;
idx = str;
char* b;
b=a;
while (*str !='\0')
{
str++;
}
while (*b!='\0')
{
*(str++) = *(b++);
}
*str = '\0';
str = idx;
};
void print() {
cout << str;
};
};
int main()
{
char lang[100];
for (int i = 0; i < 100; i++) { lang[i] = NULL; }
string comd;
cout << "First String : ";
cin >> lang;
class My_string My_comd(lang);
while (1) {
cout << "Please Enter Command(strlen,strcpy,strcat,print,quit) : ";
cin >> comd;
if (comd == "strlen") {
cout << "String length : " << My_comd.my_strlen() << endl;
continue; }
else if (comd == "strcpy") {
cin >> lang;
My_comd.my_strcpy(lang);
cout << "Strcpy is done" << endl;
continue;
}
else if (comd == "print") {
cout << "Current String : ";
My_comd.print();
cout << endl;
continue;
}
else if (comd == "strcat") {
cin >> lang;
My_comd.my_strcat(lang);
cout << "strcat is done" << endl;
continue;
}
else if (comd == "quit") {
cout << "종료하겠습니다.";
break;
}
}
return 0;
} 이 코드에서 CLASS 안에있는 MY_STRCAT 멤버함수를 호출 할 때만 오류가 발생하는데 어떻게 고쳐야할까요? 구글링해도 문제를 잘 모르겠네요
1 답변
-
왜 이런 일이 발생하나요?
캐릭터 포인터(
char *
)는 문자열과 비슷해 보이지만 일반적인 다른 언어에서의 문자열을 생각한다면 오류가 마구마구 생길 수 있습니다.C/C++에서 포인터는 쉽게 말하면 메모리 상의 위치를 나타내는
int
입니다.lang
에"shiftpsh"
를 입력받은 상황에서 메모리 공간을 대략적으로 나타내 보면 이렇습니다.... s h i f t p s h NULL NULL NULL ... ^ lang
이 때
My_string
생성자를 관찰해 보면 이렇습니다.private: char *str; public: My_string(char *a) { str = a; };
앞서
char *
는 메모리 상의 위치를 나타내는int
같은 존재라고 언급했습니다.str = a
를 하면str
에는a
의 메모리 상의 위치 정보가 저장됩니다.중요한 것은 위치 정보의 복사는 일어나지만 실제로 그 위치에 있는 문자열의 복사는 일어나지 않는다는 것입니다. 그래서
lang
과str
은 같은 메모리 공간을 공유하게 됩니다. 메모리 공간은 이렇게 됩니다.... s h i f t p s h NULL NULL NULL ... ^ lang 이면서 동시에 My_comd의 str
자, 이제
strcat
을 실행하고 두 번째 문자열"asdf"
를 입력받습니다. 여기서 문제가 발생합니다.cin >> lang
을 하고 있는데, 메모리 공간에서str
는lang
과 같은 메모리 공간을 공유하고 있다고 했습니다.lang
을 다시 입력받으면 메모리 공간은 이렇게 됩니다.... s h i f t p s h NULL NULL NULL ... ↓ lang에 "asdf" 입력 ... a s d f NULL NULL NULL ... ^ lang[0] 이면서 동시에 My_comd의 str[0]
엇,
str
을 건드리지 않았는데str
도 덩달아 바뀌었습니다.my_strcpy
함수도 체크해 볼까요?void my_strcat(char *a) { char *idx; idx = str; char *b; b = a; while (*str != '\0') { str++; } while (*b != '\0') { *(str++) = *(b++); } *str = '\0'; str = idx; }; // ... My_comd.my_strcat(lang);
일단
a
로lang
을 제공합니다. 앞서 언급한 것과 같이a
는lang
의 메모리 상의 위치입니다.lang
은 이미str
와 같은 메모리 위치를 공유한다고 했습니다. 따라서 이런 상황이 연출됩니다.... a s d f NULL NULL NULL ... ^ lang = str = idx = a = b
자, 여기서
str
만 최초의\0
이 등장할 때까지 증가시켜 봅시다.... a s d f NULL NULL NULL ... ^ ^ | str | lang = idx = a = b
이제
b
도 최초의\0
이 등장할 때까지 증가시키는 과정을 관찰해 봅시다.... a s d f NULL NULL NULL ... ^ ^ b str ↓ *(str++) = *(b++); ... a s d f a NULL NULL NULL ... ^ ^ b str ↓ *(str++) = *(b++); ... a s d f a s NULL NULL NULL ... ^ ^ b str ↓ *(str++) = *(b++); ... a s d f a s d NULL NULL NULL ... ^ ^ b str ↓ *(str++) = *(b++); ... a s d f a s d f NULL NULL NULL ... ^ ^ b str ↓ *(str++) = *(b++);
의도치 않았지만 무한 루프가 실행되는 것을 알 수 있습니다.
b
와str
이 초기에 같은 메모리 공간을 참조하고 있어서, 결국에는 같은 문자열에서 연산을 하고 있었기 때문입니다. 이 함수는 이렇게 계속 실행되다가 처음에 정해 준lang
의 크기(100
)를 넘어가면 할당되지 않은 메모리 공간을 참조해 segmentation fault 날 것입니다.어떻게 해결하나요?
malloc
,new char[N]
등의 방법으로, 메모리 공간에lang
과 다른 독립된 공간을 마련해 줘야 합니다. "C/C++ 메모리 할당" 등의 키워드로 검색해 보세요.malloc
과new
의 간략한 활용법은 이렇습니다.char* str = (char*) malloc(N * sizeof(char)); // or char* str = new char[N];
둘 모두
\0
을 포함해 길이N
의 문자열을 저장할 수 있는 새로운 메모리 공간을 할당합니다.malloc
은 C 함수로, 몇 바이트를 할당할지 명시해 줘야 합니다. 이 경우N * sizeof(char)
만큼을 할당하면 됩니다.new
는 C++ 키워드로, 몇 바이트를 할당할지 명시해 줄 필요는 없습니다.
그리고 코드를 작성할 때
char *
를 할당하는 것은 메모리 공간 상의 위치만을 복사한다는 것을 잊지 말아야 합니다. 따라서 문자열을 복사하고 싶다면 문자열 안에 있는 문자들을 하나 하나 복사해야 합니다.for
-문을 돌려서 해결해도 되고, 과제에서 요구할 경우 그렇게 하는 게 맞겠으나, 이런 메모리 복사 작업은 굉장히 자주 일어나는 작업이고 최적화 여지가 있기 때문에 C의memcpy
, C++의std::copy
등 미리 정의된 함수들을 사용할 수도 있겠습니다.new
와for
-루프를 활용하여 생성자를 고치면 이렇게 되겠습니다.private: char *str; public: My_string(char *a) { str = new char[100]; for (int i = 0; i < 100; i++) { str[i] = a[i]; } }; ~My_string() { delete str; };
my_strcat
등의 함수도 같은 방법으로 고칠 수 있겠습니다.
댓글 입력