동적 메모리 할당 (malloc/free)
지금까지 배열을 선언할 때는 int arr[10];처럼 크기를 미리 정해놓고 사용했습니다. 그런데 실제 프로그램을 만들다 보면 “사용자가 몇 개의 데이터를 입력할지 실행하기 전까지는 모른다”는 상황을 자주 만나게 됩니다. 이럴 때 배열 크기를 무작정 크게 잡아두면 메모리가 낭비되고, 너무 작게 잡으면 데이터가 넘칠 수 있습니다. 이 문제를 해결해주는 것이 바로 동적 메모리 할당입니다. 오늘은 malloc과 free를 중심으로 프로그램 실행 중에 메모리를 직접 할당하고 반납하는 방법을 알아보겠습니다.
동적 메모리 할당이 왜 필요한가
우리가 지금까지 써온 배열이나 변수는 컴파일할 때 크기가 이미 정해지는 “정적” 메모리입니다. 반면 동적 메모리는 프로그램이 실행되는 도중에, 필요한 만큼만 메모리를 요청해서 사용하는 방식입니다. C언어에서는 stdlib.h 헤더에 있는 malloc, calloc, realloc, free 함수를 이용해서 이 작업을 처리합니다. 그중에서도 가장 기본이 되는 것은 malloc(메모리를 할당)과 free(할당한 메모리를 반납)입니다.
malloc으로 메모리 할당하기
malloc 함수는 원하는 바이트 수만큼 메모리를 힙(heap) 영역에서 할당받고, 그 메모리의 시작 주소를 반환합니다. 만약 메모리를 할당하는 데 실패하면 NULL을 반환하므로, 반환값을 반드시 확인하는 습관을 들이는 것이 좋습니다.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
int *arr;
printf("정수를 몇 개 입력하시겠습니까? ");
scanf("%d", &n);
arr = (int *)malloc(n * sizeof(int));
if (arr == NULL) {
printf("메모리 할당에 실패했습니다.\n");
return 1;
}
for (int i = 0; i < n; i++) {
arr[i] = (i + 1) * 10;
}
printf("입력받은 개수만큼 동적 배열을 채웠습니다.\n");
for (int i = 0; i < n; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
free(arr);
arr = NULL;
return 0;
}
실행할 때 5를 입력했다고 가정하면 다음과 같은 결과가 출력됩니다.
정수를 몇 개 입력하시겠습니까? 5
입력받은 개수만큼 동적 배열을 채웠습니다.
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
여기서 malloc(n * sizeof(int))는 정수 n개를 담을 수 있는 크기의 메모리를 요청한다는 뜻입니다. sizeof(int)를 곱해주는 이유는 malloc이 요구하는 인자가 “바이트 수”이기 때문입니다. 할당받은 메모리는 배열처럼 arr[i] 형태로 접근할 수 있고, 사용이 끝나면 free(arr)로 반드시 반납해야 합니다. 메모리를 반납한 뒤에는 arr = NULL;처럼 포인터를 비워주면, 실수로 이미 반납된 메모리에 다시 접근하는 사고를 줄일 수 있습니다.
calloc과 realloc도 함께 알아두기
malloc과 비슷하지만 조금씩 다르게 동작하는 함수들도 있습니다. calloc은 할당과 동시에 메모리를 0으로 초기화해주고, realloc은 이미 할당된 메모리의 크기를 나중에 늘리거나 줄일 때 사용합니다.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *arr = (int *)calloc(3, sizeof(int));
printf("calloc 직후 값: %d %d %d\n", arr[0], arr[1], arr[2]);
arr = (int *)realloc(arr, 5 * sizeof(int));
arr[3] = 100;
arr[4] = 200;
printf("realloc 이후 값: %d %d %d %d %d\n",
arr[0], arr[1], arr[2], arr[3], arr[4]);
free(arr);
return 0;
}
이 코드를 실행하면 다음과 같이 출력됩니다.
calloc 직후 값: 0 0 0
realloc 이후 값: 0 0 0 100 200
calloc(3, sizeof(int))는 정수 3개 크기의 메모리를 할당하면서 모든 값을 0으로 초기화합니다. 이후 realloc(arr, 5 * sizeof(int))를 호출하면 기존 메모리 내용은 그대로 유지한 채 크기만 5개로 늘어나고, 새로 늘어난 공간에 값을 채워서 사용할 수 있습니다.
코드 동작 설명 및 예상 실행 결과
- 첫 번째 예제는 사용자가 입력한 개수만큼
malloc으로 동적 배열을 만들고, 값을 채운 뒤 출력하고free로 메모리를 반납합니다. malloc의 반환값이NULL인지 확인하는 것은 실무에서도 매우 중요한 습관이며, 이를 생략하면 메모리 부족 상황에서 프로그램이 갑자기 죽을 수 있습니다.- 두 번째 예제는
calloc으로 초기화된 메모리를 할당한 뒤,realloc으로 크기를 늘려 기존 값은 유지하면서 새로운 값을 추가로 저장합니다. - 두 예제 모두
gcc 파일명.c -o 실행파일로 컴파일 후 실행하면 위와 같은 결과를 확인할 수 있습니다.
핵심 요약
- 동적 메모리 할당은 프로그램 실행 중에 필요한 만큼 메모리를 힙에서 직접 요청하고 사용하는 방법입니다.
malloc(바이트 수)는 메모리를 할당하고 시작 주소를 반환하며, 실패하면NULL을 반환하므로 항상 확인해야 합니다.calloc은 할당과 동시에 메모리를 0으로 초기화하고,realloc은 이미 할당된 메모리의 크기를 조정할 때 사용합니다.- 동적으로 할당한 메모리는 사용이 끝나면 반드시
free로 반납해야 하며, 반납 후 포인터를NULL로 초기화하면 실수를 줄일 수 있습니다.
다음 편에서는 프로그램이 종료된 뒤에도 데이터를 남겨두고 싶을 때 사용하는 “파일 입출력”을 주제로 다뤄보겠습니다.