[C] 힙 & 동적 메모리 할당

2 minute read

이전 post에서는 정해진 크기 변수형과 함께 선언하여 사용하는 배열 형태를 살펴봤었다. 하지만 이렇게 배열의 크기를 정해서 일정 공간의 메모리를 사용하는 정적 메모리 할당 방법은 한정적인 크기를 유지하면서 사용해야한다는 점에서 메모리가 낭비된다. 동적 메모리 할당은 Heap 영역을 사용하여, 메모리 영역을 할당하고 해제할 수 있기 때문에 시스템의 메모리를 효율적으로 관리할 수 있다.

Heap 영역을 통해 동적으로 메모리를 할당하기 위해서 포인터 변수를 사용한다. 포인터 관련 글에서 살펴보았듯이 변수를 선언한 뒤 초기화할 때 주소 값을 대입하거나, 값이 기록된 주소를 참조하여 전달하는 방법이 있었다. 동적 메모리 할당을 위해서는 위의 두 방법이 아닌 메모리 영역을 얼마나 사용할 것 인지부터 선언한다. 이때 사용하는 함수들이 malloc, calloc, realloc, free 와 같은 함수들이며 stdlib.h 에 저장되어 있다.

Name Expression
malloc void * malloc (size)
calloc void * calloc (number, size)
realloc void * realloc (void * ptr, size)
free void free (void *ptr)

함수형을 보면 모두 void 형태이기 때문에 변수에 대입시 캐스팅을 통해 변수 타입을 일치시켜야한다. 먼저 malloc의 경우 할당할 메모리 영역의 크기를 인자로 전달하고, calloc의 경우 사용할 변수의 수와 단위 크기를 입력으로 넣어 number * size 만큼의 공간을 할당받는다. realloc 의 경우 메모리 영역을 재할당하는 함수로 영역을 축소, 확대 그리고 반환할 수 있다.

#include <stdio.h>
#include <stdlib.h>

int *a;
int *b;

int main(){
    a = (int*)malloc(4*5);
    if(a==0x00) return 0;

    for(int i=0; i<5; i++){
        *(a+i)=i;
        printf("%d ", *(a+i));
    }

    b = (int*)malloc(5 * sizeof(int));

    if(b==NULL) return 0;

    for(int i=0; i<5; i++){
        b[i]=i;
        printf("%d ", b[i]);
    }
    free(a);
    free(b);
    return 0;
}
0 1 2 3 4 0 1 2 3 4
#include <stdio.h>
#include <stdlib.h>
int *p;

int main(){
    p = (int *)malloc (5 * sizeof(int));
    for(int i=0; i<5; i++){
        p[i]=i;
        printf("%d ", p[i]);
    }

    p= (int*)realloc(p, 10*sizeof(int));

    for(int i=5; i<10; i++){
        p[i]=i;
        printf("%d ", p[i]);
    }

    realloc(p, 0);
    return 0;
}

0 1 2 3 4 5 6 7 8 9

배열에도 2차원 배열이 있던 것 처럼 포인터를 활용한 동적 메모리 할당 또한 2차원 배열형태를 구현할 수 있다. 이중 포인터를 사용하고, 반복문을 사용하여 동적 메모리를 할당하는 방법을 사용한다. 처음 이중 포인터에 세로길이에 해당하는 만큼의 메모리를 할당한다. 이후 선언된 각각의 포인터 배열에 가로 길이만큼의 메모리를 할당함으로써 깊이 2, 혹은 2차원의 배열을 선언할 수 있다. 이후 포인터는 동적 메모리를 반환하기 위해 행 길이만큼의 for loop를 수행하며 열방향 메모리를 반환하고 이중포인터의 동적 메모리를 반환한다.

#include <stdio.h>
#include <stdlib.h>    

int **a;

int main()
{
    **a = (int**)malloc(sizeof(int *) * 2);   

    for (int i = 0; i < 2; i++){
        a[i] = malloc(sizeof(int) * 2);   
    }

    a[0][0] = 1;  
    a[0][1] = 2;
    a[1][0] = 3;    
    a[1][1] = 4;   

    printf("%d ", a[0][0]);
    printf("%d ", a[0][1]);
    printf("%d ", a[1][0]);
    printf("%d ", a[1][1]);

    for (int i = 0; i < 2; i++){
        free(a[i]);               
    }

    free(a);   
    return 0;
}
1 2 3 4