모두의 코드 커뮤니티

C++ 버퍼오버런 이유와 해결방법

#include <iostream>
#include <string.h>
#pragma warning (disable : 4996)
class string {
	char* str;
	int len;
public:
	string(char c, int n);	// 문자 c 가 n 개 있는 문자열로 정의
	string(const char* s);	// s라는 문장을 담는다
	string(const string& s);	// 복사 생성자
	~string();

	void add_string(const string& s);	// str뒤에 s를 붙인다.
	void copy_string(const string& s);	// str에 s를 복사한다
	int strlen_();	// 문자열 길이 리턴 
	void show_status();
};
string::string(char c, int n) {
	std::cout << "생성자 실행!" << std::endl;
	int i;
	str = new char[n + 1];	

	for (i = 0; i < n; i++) {
		str[i] = c;
	}
	str[n + 1] = NULL;
	len = n;
	std::cout << "length : " << len << std::endl;
	std::cout << "string : " << str << std::endl;
}
string::string(const char* s) {
	std::cout << "생성자 실행" << std::endl;
	len = (int)strlen(s);
	str = new char[len + 1];

	strcpy(str, s);
	std::cout << "length : " << len << std::endl;
	std::cout << "string : " << str << std::endl;

}
string::string(const string& s) {
	std::cout << "복사 생성자 실행!" << std::endl;
	len = s.len;
	str = new char[s.len + 1];
	
	strcpy(str, s.str);
	std::cout << "length : " << len << std::endl;
	std::cout << "string : " << str << std::endl;
}
string::~string() {
	std::cout << "소멸자 실행!" << std::endl;
	if (str != NULL) {
		delete[] str;
	}
}
void string::add_string(const string& s) {
	int a = 0;
	std::cout << "add string..." << std::endl;

	char* temp = str;	// 새롭게 str의 메모리를 할당하게 되면 원래 있던 내용을 찾기 힘드므로 다른 곳에 잠깐 옮겨두기
	std::cout << "temp : " << temp << std::endl;

	str = new char[len + s.len + 1];
	strcpy(str, temp);
	std::cout << "str : " << str << std::endl;

	for (a = 0; a <= s.len; a++) {
		str[len + a] = s.str[a];
	}
	//str[len + s.len + 1] = NULL;
	std::cout << "END of add string..." << std::endl;
}
void string::copy_string(const string& s) {
	std::cout << "copy string" << std::endl;

	str = new char[s.len + 1];
	strcpy(str, s.str);

	std::cout << "END of copy string" << std::endl;
}
int string::strlen_() {
	return len;
}
void string::show_status() {
	std::cout << str << std::endl;
}
int main() {

	string str1('a', 7);
	string str2("hi_userrr");
	string str3 = str2;
	
	str1.show_status();
	str2.show_status();
	str3.show_status();

	str1.add_string(str2);
	str3.copy_string(str1);

	str1.show_status();
	str2.show_status();
	str3.show_status();
	return 0;
}

위는 제 코드이고 “씹어먹는C++” 4-3 스타크래프트 만들기 예제1번인 문자열 클래스 완성하기 문제인데 원하는 결과는 나오는데 소멸자가 하나만 실행되고 비정상적으로 프로그램이 중단되며 사진과 같이 에러가 발생했습니다
질문(1)
어디서 버퍼오버런이 발생한지 모르겠습니다 VS에서는 27번째 줄인 str[n + 1] = NULL; 라고 하는데 이해가 되지 않습니다 제가 보기에는 맞는 입력이였던 것 같은데 어디가 잘못됐는지 알려주시면 감사하겠습니다

질문(2)

     void string::add_string(const string& s) {
        	int a = 0;
        	std::cout << "add string..." << std::endl;

        	char* temp = str;	// 새롭게 str의 메모리를 할당하게 되면 원래 있던 내용을 찾기 힘드므로 다른 곳에 잠깐 옮겨두기
        	std::cout << "temp : " << temp << std::endl;

        	str = new char[len + s.len + 1];
        	strcpy(str, temp);
        	std::cout << "str : " << str << std::endl;

        	for (a = 0; a <= s.len; a++) {
        		str[len + a] = s.str[a];
        	}
        	//str[len + s.len + 1] = NULL;
        	std::cout << "END of add string..." << std::endl;
        }

add_string 함수에서 str을 새롭게 동적할당을 할때 기존에 동적할당된 메모리는 delete[] str로 지우고 다시 할당해야 맞는거 아닌가요?
std::cout << "temp : " << temp << std::endl;
if (str != NULL) {
delete[] str;
}
str = new char[len + s.len + 1];
이렇게 하니 오류가 발생하였습니다 이 부분도 제가 뭘 잘못하고 있는건지 알려주시면 정말 감사하겠습니다

질문(3)

그리고 한 가지 더 궁금한 점은 여기서 string 클래스에서 int strlen_(); 함수를 왜 사용하는 것 인가요? 직접 string클래스의 멤버인 len을 사용하면 더 편리하지 않나요??

답변 해주셔서 정말 감사합니다!

코드의 가장 큰 문제점

배열의 시작은 0 입니다.

char str[6] = "hello"; // str[0] ~ str[5], (str[6] <- error)

위 코드로 예를 들자면, 0~5 까지 총 여섯 가지의 공간이 있기 때문에 str[6] 은 있을 수 없습니다.
하지만 올려주신 코드에는 배열의 영역을 넘어간 다른 영역까지 사용되었습니다.

strlen_() 함수를 사용하는 이유

len 변수는 private field 에 있습니다. 때문에 함수를 사용해서 길이를 반환해요.
이런 경우를 encapsulation 이라고 해요, 객체지향의 몇 가지 요소 중 하나 입니다.

감사합니다 덕분에 문제가 해결되었습니다

좋아요 1

다행이네요 : )