• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    해결됨

메모리 할당 해제 이후의 배열 원소 접근 문제

22.01.08 00:20 작성 조회수 225

0

#include <iostream>

using namespace std;

int main()
{
	const int row = 3;
	const int col = 5;

	// 복사할 2차원 배열
	const int s2da[row][col] =
	{
		{1, 2, 3, 4, 5},
		{6, 7, 8, 9, 10},
		{11, 12, 13, 14, 15}
	};

	// twoDimArr의 row 배열을 가리킬 포인터를 초기화한다.
	int **twoDimArr{ new int *[row] {nullptr} };

	// row 배열을 할당한다.
	for (int r = 0; r < row; ++r)
		twoDimArr[r] = new int[col] { 0 };

	// s2da에서 twoDimArr로 복사한다.
	for (int r = 0; r < row; ++r)
	{
		for (int c = 0; c < col; ++c)
			twoDimArr[r][c] = s2da[r][c];
	}

	// row 배열(twoDimArr[0...2])을 할당 해제한다.
	for (int r = 0; r < row; ++r)
		delete[] twoDimArr[r];

	// *****************************************************************
	int *ptr{ new int { 3 } };
        delete ptr;
	
	//cout << *ptr << endl;				// 오류

	// row 배열 할당 해제로 인해 해당 배열의 원소를 접근할 수 없다.
	cout << **twoDimArr << endl;		// twoDimArr[0][0]
	// *****************************************************************

	// 2차원 배열(twoDimArr)을 할당 해제한다.
	delete[] twoDimArr;

	return 0;
}

(visual studio 2019에서 작성한 코드입니다.)

위 코드에서, ptr은 할당 해제 후에 접근하면 오류가 발생해 프로그램이 강제로 종료됐습니다.

 

그러나, twoDimArr의 row 배열들(twoDimArr[0...2])을 할당 해제하고 **twoDimArr 출력을 시도했을 때 프로그램이 종료되지 않았습니다.

 

ptr처럼 할당을 해제하고 접근했다면, 프로그램이 비정상적인 종료를 해야하지 않나요?

게다가 intellisense에서 첫 번째 경우는 경고를 하는 반면에, 두 번째 경우는 그렇지 않네요.

ps. 이렇게 사용하는 것은 올바르지 못한 것을 알지만, 생각과 다르게 실행된 이유가 궁금합니다.

답변 1

답변을 작성해보세요.

3

강민철님의 프로필

강민철

2022.01.09

안녕하세요 :)

결론부터 말씀드리자면, 

제시해주신 코드에서 아래의 부분과 

 

// row 배열(twoDimArr[0...2])을 할당 해제한다.
for (int r = 0; r < row; ++r)
	delete[] twoDimArr[r];

 

2차원 배열를 해제하는 아래의 부분 사이에 출력이 있었기 때문입니다.

delete[] twoDimArr;

 

ptr는 하나의 메모리 공간을 가리키는 포인터이므로 

이것이 해제되었을 때 컴파일러는 명백하게 할당된 공간이 해제되었음을 알 수 있습니다.

 

하지만 이차원 배열은 그 크기가 가변적이기 때문에 

배열의 메모리 공간을 완전하게 해제했음을 알려주기 위해서는 

일부 원소만이 아닌 2차원 배열 변수를 포함해 끝까지 delete 해야 합니다.

(메모리 상으로는 제시해주신 코드가 맞으나, 

컴파일러 입장에서 메모리가 해제되었음을 인지하려면

아래처럼 2차원 배열을 끝까지 해제해야 합니다)

 

delete[] twoDimArr;

 

첨언을 드리자면, 이는

어느 정도 컴파일러에 의존적인 결과로 보입니다.

첨부해주신 Visual Studio 2019나 g++ 에서는 

(비록 권장하는 방법이 아니고, 결과적으로 쓰레기 값이 나오지만)

아래처럼 중간 종료 없이 컴파일 자체는 가능하지만,

 

$ g++ arr.cc  # 컴파일 성공

$ g++ --version
g++ (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 

clang과 같은 컴파일러에서는 ptr가 되었든 twoDimArr가 되었든 

에러가 발생하며 종료됩니다.

 

$ clang arr.cc
/tmp/arr-3da0fd.o: In function `main':
arr.cc:(.text+0x2c): undefined reference to `std::cout'
arr.cc:(.text+0x30): undefined reference to `std::cout'
arr.cc:(.text+0x34): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
arr.cc:(.text+0x38): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
arr.cc:(.text+0x60): undefined reference to `operator new[](unsigned long)'
arr.cc:(.text+0xd0): undefined reference to `operator new[](unsigned long)'
arr.cc:(.text+0x20c): undefined reference to `operator delete[](void*)'
arr.cc:(.text+0x22c): undefined reference to `operator new(unsigned long)'
arr.cc:(.text+0x24c): undefined reference to `operator delete(void*)'
arr.cc:(.text+0x260): undefined reference to `std::ostream::operator<<(int)'
arr.cc:(.text+0x268): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
arr.cc:(.text+0x27c): undefined reference to `operator delete[](void*)'
/tmp/arr-3da0fd.o: In function `__cxx_global_var_init':
arr.cc:(.text.startup+0x14): undefined reference to `std::ios_base::Init::~Init()'
arr.cc:(.text.startup+0x18): undefined reference to `std::ios_base::Init::~Init()'
arr.cc:(.text.startup+0x38): undefined reference to `std::ios_base::Init::Init()'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

$ clang --version
clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
Target: aarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
ubuntu@ip-172-31-24-100:~$

 

intellisense에서 첫 번째 경우는 경고를 하는 반면에, 두 번째 경우는 그렇지 않다고 하신 것도

이런 이유로 보여집니다.

 

요는, 

이차원 배열의 실제 메모리 상의 해제와는 별개로,

실제 컴파일러가 메모리가 해제가 되었음을 인지하는 것은

이차원 배열 자체의 해제가 필요할 수 있다.

정도가 될 듯 합니다.

 

답변이 되었을지는 모르겠지만, 혹시라도 추가 질문이 있으시다면 댓글 더 달아주세요!

도움이 되었길 바랍니다 :) 

 

감사합니다.

 

새해 복 많이 받으세요.

9iraffe님의 프로필

9iraffe

질문자

2022.01.09

아하 의외로 이런 부분에서 컴파일러의 차이를 확인할 수 있네요...

처음 알았습니다. 답변해주셔서 감사합니다!

 

새해 복 많이 받으세요.