메모리 동적 할당
"스택" 세그먼트 공간에 메모리를 할당 하는 방법인 지역변수들을 사용했었습니다.
지역변수들은 함수가 호출될때마다 새롭게 생겨나기에, 별도의 관리가 필요없는 장점이 있지만 자료의 형태, 자료의 크기를 미리 예상하여 할당을 해 두어야 합니다.
99%의 확률로 3 ~ 4byte 만 사용하지만, 1% 확률로 10000byte 가 필요하다고 하면,
어쩔 수 없이 10000byte 를 변수(배열)로 선언해 두어야 합니다. 이는 매우 불합리하며 비 효율적인 상황입니다.
따라서, 프로그램의 런타임(동작중)에 메모리를 할당하고 사용할 수 있는 방법이 필요했고, 이를 "동적 메모리 할당"이라고 합니다.
메모리 동적 할당 개념과 함수
"힙" 세그먼트 공간에 원하는 만큼 공간을 할당한 다음, 그 첫 메모리 주소를 돌려줍니다.
여러 세그먼트로 나뉘어 있더라도 결국은 가상 메모리 4GB(32bit 기준)안의 어느 한 지점입니다.
따라서 언제든지 메모리 주소로 표현 및 접근 할 수 있습니다.
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char** argv)
{
int SizeN = 10;
int* intPtr = (int*)malloc(sizeof(int) * SizeN);
intPtr[0] = 1;
intPtr[1] = 3;
printf("%d %d",intPtr[0],intPtr[1]);
free(intPtr);
return 0;
}
동적으로 메모리를 할당 및 해제 하기 위해 malloc 함수와 free 함수를 사용 했습니다.
- stdlib.h를 include 하면 이 함수를 찾을 수 있습니다.
malloc
malloc 은 메모리를 할당하는 함수입니다. 인수는 할당할 byte 의 수 이며 리턴값은 할당한 메모리의 포인터 입니다.
리턴 값은 void* 형으로 들어오게 되는데, 이는 어떠한 자료형의 메모리 주소값이라도 표기 할 수 있기 때문입니다.
정확히는 malloc 는 자료형을 전혀 신경쓰지 않으며 해당한 byte 의 크기만큼을 할당해서 돌려줍니다. 이 byte 뭉치를 어떻게 나누어 쓰는지에 대해서는 전적으로 프로그래머의 몫입니다.
int* intPtr = (int*)malloc(sizeof(int) * SizeN);
sizeof 연산자는 해당하는 자료형의 크기를 알 수 있습니다.
- sizeof 는 함수처럼 생겼지만 함수가 아니라 연산자입니다. 확인하려면 어떠한 헤더파일도 include 하지 않고 sizeof 를 호출해 보세요.
- sizeof(int)는 int 형의 크기인 4byte 를 돌려줄 것입니다.
SizeN 변수에 10을 넣었으므로, malloc 함수는 최종적으로 40 byte 의 메모리 뭉치를 돌려줄 것입니다.
이 메모리 주소는 void*로 들어오므로, (int*) 캐스팅을 통해 int 형 포인터에 대입시켰습니다.
결론적으로 int intPtr[10]; 을 선언한것과 동일한 효과를 얻은 것입니다.
- 전자는 힙, 후자는 스택 세그먼트입니다.
free
free 는 메모리 할당을 해제하는 함수입니다
스택에 생성된 메모리와는 다르게 malloc 로 할당한 메모리는, 프로그램이 종료될 때까지 자동으로 해제되지 않습니다.
따라서 해당 메모리가 불필요해 지게 된다면, free 로 해제해 주어야 합니다.
new / delete (C++)
C++ 에서는 new 혹은 delete 키워드 힙에 메모리 할당을 할 수 있습니다. 이 키워드는 class 를 위한 키워드 이지만, 다른 자료형에도 사용할 수 있습니다.
다만, malloc / free 와 new / delete 를 혼용하지 않아야 합니다.
new / delete 는 class 의 생성자와 소멸자를 호출시키는 기능을 가지고 있기 때문에, malloc 으로 할당한 힙 메모리를 delete 로 삭제하는 등의 케이스에서 문제를 발생시킬 수 있습니다.