32.1 메모리 할당하기

메모리를 사용하려면 malloc 함수로 사용할 메모리 공간을 확보해야 합니다(memory allocation). 이때 필요한 메모리 크기는 바이트 단위로 지정합니다(메모리 할당, 해제 함수는 stdlib.h 헤더 파일에 선언되어 있습니다).

  • 포인터 = malloc(크기);
    • void *malloc(size_t _Size);
    • 성공하면 메모리 주소를 반환, 실패하면 NULL을 반환

다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요. 만약 컴파일할 때 "error C2440: '=': 'void *'에서 'int *'(으)로 변환할 수 없습니다." 에러가 발생한다면 파일의 확장자가 .c가 맞는지 확인하세요. 파일 확장자가 .cpp이면 C++ 컴파일러를 사용하므로 에러가 발생합니다. 확장자는 반드시 .c로 지정하여 C 컴파일러를 사용하도록 만들어야 합니다.

memory_alloc.c

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

int main()
{
    int num1 = 20;    // int형 변수 선언
    int *numPtr1;     // int형 포인터 선언

    numPtr1 = &num1;  // num1의 메모리 주소를 구하여 numPtr에 할당

    int *numPtr2;     // int형 포인터 선언

    numPtr2 = malloc(sizeof(int));    // int의 크기 4바이트만큼 동적 메모리 할당

    printf("%p\n", numPtr1);    // 006BFA60: 변수 num1의 메모리 주소 출력
                                // 컴퓨터마다, 실행할 때마다 달라짐

    printf("%p\n", numPtr2);     // 009659F0: 새로 할당된 메모리의 주소 출력
                                // 컴퓨터마다, 실행할 때마다 달라짐

    free(numPtr2);    // 동적으로 할당한 메모리 해제

    return 0;
}

실행 결과

006BFA60 (메모리 주소. 컴퓨터마다, 실행할 때마다 달라짐)
009659F0 (메모리 주소. 컴퓨터마다, 실행할 때마다 달라짐)

메모리를 할당할 때는 malloc 함수를 사용하며 할당할 메모리 공간의 크기를 넣어줍니다. 여기서는 sizeof 연산자를 사용하여 int의 크기(4바이트)만큼 메모리를 할당했습니다. 특히 원하는 시점에 원하는 만큼 메모리를 할당할 수 있다고 하여 동적 메모리 할당(dynamic memory allocation)이라 부릅니다.

numPtr2 = malloc(sizeof(int));    // int의 크기 4바이트만큼 동적 메모리 할당

printf 함수로 numPtr1numPtr2의 값을 출력해보면 메모리 주소가 출력됩니다.

printf("%p\n", numPtr1);    // 006BFA60: 변수 num1의 메모리 주소 출력
                            // 컴퓨터마다, 실행할 때마다 달라짐

printf("%p\n", numPtr2);    // 009659F0: 새로 할당된 메모리의 주소 출력
                            // 컴퓨터마다, 실행할 때마다 달라짐

여기서 numPtr1에는 일반 변수의 메모리 주소를 할당했고, numPtr2에는 malloc 함수로 메모리를 할당했습니다. 같은 메모리 주소라도 내부적으로는 약간의 차이가 있습니다. 스택과 힙 두 가지인데 변수는 스택(stack)에 생성되며 malloc 함수는 힙(heap) 부분의 메모리를 사용합니다(스택, 힙의 위치와 커지는 방향은 운영체제 및 플랫폼에 따라 달라질 수 있습니다).

그림 32-2 스택과 힙(Windows x86/32비트)

스택과 힙의 큰 차이점은 메모리 해제입니다. 스택에 생성된 변수는 사용한 뒤 따로 처리를 해주지 않아도 되지만 malloc 함수를 사용하여 힙에서 할당한 메모리는 반드시 해제를 해주어야 합니다. 따라서 다음과 같이 free 함수로 메모리를 해제합니다.

  • free(포인터);
    • void free(void *_Block);
free(numPtr2);    // 동적으로 할당한 메모리 해제

메모리 해제는 선택이 아닌 필수입니다. 예제는 별로 하는 일이 없는 간단한 프로그램이지만 실무에서는 메모리를 자주, 많이 할당합니다. 따라서 메모리를 할당만 하고 해제를 해주지 않으면 결국에는 시스템의 메모리가 부족해지므로 운영체제가 프로그램을 강제로 종료시키거나 메모리 할당에 실패하게 됩니다. 특히 메모리를 해제하지 않아 메모리 사용량이 계속 증가하는 현상을 메모리 누수(memory leak)라 부릅니다.