컴퓨터 구조/C, C++

C/C++ 동적 할당

JiHxxn 2024. 8. 18. 12:00

🤔 정적 할당과 동적 할당의 차이

정적 할당(Static Allocation)  동적 할당(Dynamic Allocation)
컴파일 타임에 메모리 할당 런타임에 필요한 만큼 메모리 할당
미리 할당 받기 때문에 동적 할당보다 빠름 실핼 중 논리적으로 옳고 그름을 따져 할당 받기 때문에 느림
프로그램 종료 시 자동으로 메모리 반환 사용자가 직접 메모리 반환 해주어야 함

🤔 Heap 메모리 사용 조건

  • 무조건 포인터를 사용해야 한다.
    • 결국은 heap의 주소를 저장하는 것이기 때문
  • Heap 메모리에 할당을 했다면 해제(반환)도 꼭 해주어야 한다. 필연적.
    • 메모리 누수(memory leak)를 방지하기 위함. + 댕글리 포인터 방지.
  • 현재는 운영체제가 해제되지 않은 메모리를 회수하지만 이는 운영체제가 문제를 복구하기 위한 작업이므로, 개발자가 정확한 할당과 해제를 해주어야 한다.

댕글링 포인터

  • 반환까지 해주었지만, c언어 시절 그 주소로 다시 접근할 수 있었다.
    • 문제가 되는 이유는 사용허가 내리지 않은 메모리 주소에 접근할 수 있어서이다.
  • 그래서 항상 반환 함수(free)를 사용 후 변수에 NULL, nullptr을 대입해 초기화해준다.

메모리 누수(memory lick)

  • heap 메모리에 올렸다가 적당히 필요 없는 시점에서 해제해주지 않아 발생한다.
  • 제대로 제거해주지 않아 쌓이다 보면 프로그램이 응답하지 않거나, 강제 종료된다.

🚚 c언어의 동적 할당 2가지 함수

malloc (memory allocation) clloc (contiguous allocation)
먼저 나온 동적 할당 함수 malloc 이후 나온 동적 할당 함수
선언 시 쓰레기 값으로 초기화 됨 선언 시 자동으로 0으로 초기화 됨

malloc (memory allocation)

void* malloc(size_t _Size); // malloc 원형
// 보이드 포인터(void*)
    // 어떤 반환값이 올 지 모르기 때문에 default로 void로 설정.
    
int* p = (자료형*)malloc(자료형 크기); // 사용 방법
  • 필요한 메모리양을 바이트 단위로 전달하면 요청한 만큼 메모리를 할당하고 해당 메모리 주소를 반환

동적 배열

int* pArray = (int)malloc(sizeof(int) * 4); 
//int 자료형의 크기에서 * 4를 해주어 4byte 4개의 연속된 메모리를 할당

pArray[0] = 10;
pArray[1] = 10;
pArray[2] = 20;
pArray[3] = 30;

for(int i=0; i<sizeof(pArray); ++i)
{
	cout << p[i] << ' ';
}

**=> 10 10 20 30 출력**

clloc (contiguous allocation)

void* calloc(size_t number, size_t size); // clloc 원형

int * pArray = (자료형*)clloc(크기, 개수); // 사용 방법

동적 배열

int * pArray = (int*)clloc(sizeof(int), 4);
// 인자값으로 개수를 넣어줄 수 있는데, 배열로 만들고 싶으면 2이상의 수를 넣어주면 됨

for(int i=0; i<sizeof(pArray); ++i)
	cout << pArray[i] << ' ';
=> 0 0 0 0 출력

C 메모리 반환

free : 할당한 메모 공간을 반환하는 c언어 함수

  • heap 메모리에 할당된 주소를 반환(해제)할 때 사용한다.

사용 예시

int* pArray = (int)malloc(sizeof(int) * 4);
free(pArray);
pArray = NULL; // 댕글리 포인터 방지

int * pArray2 = (int*)clloc(sizeof(int), 4);
free(pArray2);
pArray2 = NULL; // 댕글리 포인터 방지

🚛 C++ 동적 할당

int* pNum = new int(10); //10으로 초기화하여 heap 메모리에 할당

int* pArray = new int[4]{1,2,3,4}; // 동적 배열 크기 4에 1,2,3,4 값을 초기화 하여 heap 메모리에 할당

C++ 메모리 반환

delete : 할당한 메모 공간을 반환하는 c++언어 함수

delete pNum;
delete [] pNum; // 배열은 대괄호([])를 넣어 해제 해주어야한다.

pNum = nullptr; // 주소 초기화
  • C++ 에선 메모리 해제를 해주면 자동으로 이전 주소값 말고 접근할 수 없는 주소값을 넣어 막아준다.
    • 하지만 안전하게 코딩하기 위하여 초기화해준다. pNum = nullptr

메모리 누수 체크

  • debug 모드에서만 확인 가능
  • 아래 코드 삽입 후 디버깅
//전처리 시점
#ifdef _DEBUG

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#ifndef DBG_NEW 
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ ) 
#define new DBG_NEW 

#endif
#endif

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
}

동적 할당된 변수의 주소

int main()
{
	int* p = (int*)malloc((sizeof(int));
	return 0;
}
  • 위 main 함수 안의 p는 어느 메모리 영역에 저장되어 있고, 그 이유는?
    • Stack 영역이다.
      • p(int포인터) 자체는 stack메모리 할당되어 있고, heap 주소를 저장하고 있을 뿐이다.

'컴퓨터 구조 > C, C++' 카테고리의 다른 글

다중 포인터란  (0) 2024.08.16
구조체 크기 계산법 및 최적화  (0) 2024.08.12
const와 포인터  (0) 2024.08.09
[C/C++]포인터 기초  (0) 2024.08.04
[C/C++] 함수란  (0) 2024.07.31