동적 메모리 — 유연한 데이터 관리
지금까지 우리는 데이터 개수(배열 크기)를 코딩할 때 미리 고정해야만 했습니다. 이제 프로그램이 실행되는 도중에 힙(Heap) 공간에서 필요한 만큼만 메모리를 주문하고, 다 쓰면 반납하는 고급 메모리 제어 기술을 배웁니다.
학습 목표
<stdlib.h> 라이브러리의 malloc()을 사용하여 메모리를 실시간으로 확보한다.calloc()과 크기를 연장하는 realloc()을 사용한다.free()로 반환하여 메모리 누수(Leak)를 방지한다.Student *)를 이용해 크기가 자유자재로 늘어나는 동적 배열을 설계한다.C언어 메모리의 두 기둥: 스택(Stack)과 힙(Heap)
우리가 int students[100]; 이라고 쓰면 컴파일러는 무조건 100명분의 공간을 스택(Stack)이라는 제한된 영역에 미리 잡아놓습니다. 10명만 가입해도 90명분은 버려지고, 101명째가 가입하면 프로그램이 터집니다.
이를 해결하기 위해 운영체제에게 "힙(Heap)이라는 광활한 공간에서 내가 원하는 바이트만큼만 빌려주세요!"라고 요청하는 것이 바로 동적 메모리 할당입니다.
(malloc, calloc으로 런타임에 동적으로 크기가 커졌다 작아졌다 함) ↓
↑ (함수의 지역 변수, 매개 변수가 쌓이는 공간)
메모리 대출과 반납 (malloc, free)
malloc(크기) 함수는 요청한 바이트만큼 힙에서 메모리를 떼어낸 뒤, 그 공간의 시작 주소(포인터)를 반환합니다.
#include <stdio.h> #include <stdlib.h> // malloc, free 사용을 위한 헤더 int main() { // int 5개를 담을 수 있는 메모리 주소를 p에 저장 (동적 배열) int *p = malloc(sizeof(int) * 5); // 반드시 대출에 성공했는지 검사해야 합니다! if (p == NULL) { printf("메모리 부족!\n"); return 1; } p[0] = 10; // 일반 배열처럼 똑같이 사용 가능 // 사용이 끝나면 무조건 반납! (반납 안 하면 메모리 누수 발생) free(p); return 0; }
초기화(calloc)와 크기 조절(realloc)
| 함수 | 사용법 | 특징 |
|---|---|---|
malloc() |
malloc(sizeof(int)*5) |
할당만 하고 초기화하지 않음 (쓰레기값 잔존) |
calloc() |
calloc(5, sizeof(int)) |
할당 후 모든 바이트를 0으로 덮어씀 (안전함) |
realloc() |
realloc(ptr, newSize) |
기존 데이터는 유지한 채 크기만 확장/축소 |
// 1. 처음엔 5명분 공간 확보 int *arr = malloc(sizeof(int) * 5); // 2. 공간이 모자라 10명분으로 늘리고 싶다! int *temp = realloc(arr, sizeof(int) * 10); // 3. 안전 검사 (realloc 실패 시 NULL이 반환되어 원본 주소가 날아갈 수 있음) if (temp != NULL) { arr = temp; // 안전하게 주소 덮어쓰기 }
구조체 배열을 동적으로 만들기
STEP 11에서 배운 구조체 배열 Student students[100];을 동적 배열로 바꾸면 프로그램 실행 중 입력받은 회원 수(count)만큼만 메모리를 할당할 수 있습니다.
Student *students; int count; printf("몇 명의 학생을 입력하시겠습니까? : "); scanf("%d", &count); // 사용자가 입력한 숫자만큼만 구조체 배열 생성! students = malloc(sizeof(Student) * count); // 이후 일반 구조체 배열처럼 students[i].name 형식으로 조작 가능 free(students);
메모리 누수(Memory Leak) 경고
C언어는 Java나 Python처럼 쓰레기 수집기(Garbage Collector)가 없습니다. 할당(malloc)을 했으면 무조건 해제(free)를 직접 코딩해야 합니다.
free()를 하지 않고 프로그램을 계속 돌리게 되면, 힙 영역에 사용하지 않는 쓰레기 메모리가 계속 누적됩니다. 결국 서버나 장기 실행 프로그램은 메모리 부족(OOM)으로 다운되고 맙니다. malloc을 쓰면 무의식적으로 짝꿍인 free를 가장 먼저 적어두는 습관을 들이세요.
STEP 13 최종 프로젝트
무한 확장 가능한 동적 회원 관리 프로그램
지금까지 배운 모든 C언어 스킬을 집대성합니다. 처음엔 메모리를 2명분(capacity = 2)만 할당해 놓고, 회원이 꽉 찰 때마다 realloc을 통해 메모리를 2배씩 뻥튀기시키는 벡터(Vector) 방식의 알고리즘을 직접 구현해 봅니다.
- [1]
malloc(sizeof(Member) * 2)로 시작합니다. - [2] 회원 등록 메뉴(count 증가)를 만듭니다.
- [3]
count >= capacity가 되면capacity *= 2를 하고realloc을 돌립니다. - [4] 이로써 배열 크기를 사전에 알 필요가 없는 완벽한 동적 DB가 완성됩니다!
STEP 13 완료 체크리스트
가장 어렵다고 악명 높은 [포인터 - 구조체 - 동적 메모리] 3대장 산맥을 모두 넘으셨습니다. 이제 여러분은 컴퓨터의 메모리를 자유자재로 지휘하는 시스템 프로그래머의 마인드를 갖추게 되었습니다. 다음 단계에서는 복잡한 C 프로그램을 모듈화하고 최적화하는 전처리기와 매크로(매직 키워드)의 세계를 탐험합니다.