동적 메모리 할당 (malloc, calloc, realloc, free)
in Blog / Tech Stack on 운영체제, C 언어
정적 vs 동적 할당
| 정적 할당 | 동적 할당 | |
|---|---|---|
| 영역 | 스택 | 힙 |
| 크기 | 고정 (컴파일 타임) | 유동 (런타임) |
| 관리 | 자동 해제 | free() 직접 호출 |
| 크기 한계 | 작음 (MB) | 큼 (GB도 가능) |
| 사용 예 | int arr[10] | malloc(n * sizeof(int)) |
함수별 정리

malloc — 기본 할당
void* malloc(size_t size);
- 지정한 바이트만큼 힙에 할당
- 초기화 없음 → 쓰레기값(garbage) 주의
- 실패 시
NULL반환
int* arr = (int*)malloc(5 * sizeof(int));
if (!arr) return -1; // NULL 체크 필수
calloc — 0 초기화 할당
void* calloc(size_t n, size_t size);
n개 요소 ×size바이트 할당- 전체를 0으로 초기화 → 배열에 적합
- 실패 시
NULL반환
int* arr = (int*)calloc(5, sizeof(int)); // 모두 0
malloc보다 약간 느리지만, 초기화 누락 버그를 원천 차단
realloc — 크기 변경
void* realloc(void* ptr, size_t new_size);
- 기존 할당 블록의 크기를 확장하거나 축소
- 뒤에 공간 있으면 제자리 확장 (주소 그대로)
- 뒤에 공간 없으면 새 위치로 이동 후 데이터 복사 → 기존 블록 자동 해제
- 새로 늘어난 부분은 초기화 안 됨
- 실패 시
NULL반환 (기존 포인터는 유효한 상태로 유지)
// 잘못된 방법 — 실패시 ptr이 NULL이 되어 기존 메모리 누수
ptr = realloc(ptr, new_size);
// 올바른 방법
int* tmp = realloc(ptr, new_size);
if (tmp) ptr = tmp;
REALLOC 내부동작

free — 메모리 해제
void free(void* ptr);
- 동적 할당된 메모리 반납. 사용 후 반드시 호출
- 해제 후 포인터를
NULL로 초기화하는 습관 권장
free(ptr);
ptr = NULL; // 댕글링 포인터 방지
free 하면 안 되는 경우
| 잘못된 예 | 이유 |
|---|---|
스택 변수에 free(&x) | 동적 할당된 메모리만 해제 가능 |
같은 포인터 두 번 free | Double free → 힙 손상 |
free 후 포인터 재사용 | 댕글링 포인터 → Undefined Behavior |
free 없이 종료 | 메모리 누수 |
한눈에 비교
| 함수 | 초기화 | 주요 용도 |
|---|---|---|
malloc | 없음 | 빠르게 할당만 필요할 때 |
calloc | 0으로 초기화 | 배열 등 초기화가 중요할 때 |
realloc | 새 영역 없음 | 크기를 동적으로 바꿔야 할 때 |
free | — | 사용 후 반드시 호출 |
안전한 패턴

체크리스트
malloc/calloc반환값 NULL 체크- 동적 할당 사용 후
free()호출 realloc은 반환값을 임시 변수에 먼저 받기free()후 포인터에NULL대입- 스택 변수에
free()하지 않기