프로그래밍 언어/C언어
[C 언어] 동적 메모리 할당(malloc, calloc, realloc)를 모르는 당신! 정~~~말 불쌍해!
넌뭐가그렇게중요해
2025. 4. 15. 13:55
C 언어에서 동적 메모리 할당은 프로그램 실행 중에 필요한 만큼의 메모리를 할당받아 사용하는 중요한 기능입니다. 동적 메모리 할당을 통해 배열과 같은 데이터 구조의 크기를 실행 시간에 결정할 수 있으며, 메모리의 효율적인 사용이 가능해집니다. 이때 할당되는 메모리는 Heap 영역에 위치하며, 대표적으로 사용하는 함수는 malloc, calloc, realloc입니다.
1. 메모리 구조와 Heap 영역
C 프로그램은 일반적으로 다음과 같은 메모리 영역으로 구성됨
- 코드 영역(Code Segment): 실행할 명령어들이 저장됨
- 데이터 영역(Data Segment): 전역 변수 및 static 변수 등이 저장됨
- BSS 영역: 초기화되지 않은 전역 변수 및 static 변수들이 저장됨
- Stack 영역: 함수 호출 시 생성되는 지역 변수, 매개변수, 리턴 주소 등이 저장됨
- Heap 영역: 동적 메모리 할당에 사용되는 영역으로, 프로그램 실행 중에 필요에 따라 메모리를 할당하거나 해제할 수 있음
Heap 영역은 메모리 사용량이 가변적이며, 프로그래머가 직접 메모리 할당(malloc, calloc, realloc)과 해제(free)를 관리해야 합니다.
2. 동적 메모리 할당의 필요성과 장단점
필요성 및 이유:
- 유연한 메모리 사용: 실행 시간에 메모리 요구량을 결정할 수 있어, 사용자 입력이나 데이터 양에 따라 동적으로 크기를 조절할 수 있습니다.
- 효율적 메모리 사용: 필요할 때만 메모리를 할당하여 메모리 낭비를 줄일 수 있습니다.
- 복잡한 데이터 구조 구현: 연결 리스트, 트리, 그래프 등 동적 크기가 필요한 자료구조를 구현하는 데 필수적입니다.
장점:
- 필요한 만큼의 메모리를 동적으로 할당하여 유연하게 사용할 수 있음.
- 데이터 크기에 따라 메모리 사용을 최적화할 수 있음.
단점:
- 메모리 할당과 해제를 프로그래머가 직접 관리해야 하므로, 메모리 누수나 잘못된 해제(댕글링 포인터)와 같은 버그 발생 위험이 있음.
- 할당과 해제에 따른 오버헤드가 존재.
3. 동적 메모리 할당 함수
동적 메모리 할당은 주로 아래의 함수들을 통해 이루어집니다.
3.1 malloc
- 기능: 지정한 바이트 수만큼의 메모리를 할당하고, 할당된 메모리의 시작 주소를 반환합니다.
- 특징: 초기화되지 않은 메모리를 반환하므로, 사용 전에 값을 직접 초기화해야 합니다.
- e.g.
#include <stdlib.h>
#include <stdio.h>
int main() {
// int형 10개 크기의 메모리를 할당 (Heap 영역)
int *arr = (int *)malloc(10 * sizeof(int));
if (arr == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
// 할당된 메모리 사용 (초기화 필요)
for (int i = 0; i < 10; i++) {
arr[i] = i * 2;
}
// 값 출력
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 메모리 해제
free(arr);
return 0;
}
3.2 calloc
- 기능: malloc과 유사하지만, 할당한 메모리를 모두 0으로 초기화하여 반환합니다.
- 특징: 요소의 개수와 각 요소의 크기를 인자로 받아 초기화된 메모리를 제공하므로, 초기화 작업이 필요할 때 안전하게 사용할 수 있습니다.
- e.g.
#include <stdlib.h>
#include <stdio.h>
int main() {
// int형 10개 크기의 메모리를 0으로 초기화하여 할당
int *arr = (int *)calloc(10, sizeof(int));
if (arr == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
// 할당된 메모리 사용 (이미 0으로 초기화됨)
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 메모리 해제
free(arr);
return 0;
}
3.3 realloc
- 기능: 이미 할당된 메모리 블록의 크기를 변경합니다. 기존 데이터는 유지되며, 필요한 경우 새 메모리로 옮겨집니다.
- 특징: 메모리 크기를 동적으로 조절할 때 유용하며, 크기를 확장하거나 축소할 수 있습니다.
- e.g.
#include <stdlib.h>
#include <stdio.h>
int main() {
// 처음에는 5개 크기의 int 배열을 할당
int *arr = (int *)malloc(5 * sizeof(int));
if (arr == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
// 필요에 따라 배열 크기를 10개로 확장
int *temp = (int *)realloc(arr, 10 * sizeof(int));
if (temp == NULL) {
printf("메모리 재할당 실패\n");
free(arr);
return 1;
}
arr = temp;
// 새로 할당된 메모리 부분 초기화
for (int i = 5; i < 10; i++) {
arr[i] = i + 1;
}
// 값 출력
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 메모리 해제
free(arr);
return 0;
}
결론
동적 메모리 할당은 프로그램 실행 중 필요한 만큼 메모리를 할당받아 효율적으로 사용하는 방법입니다.
- malloc: 초기화되지 않은 메모리를 할당받을 때 사용합니다.
- calloc: 할당과 동시에 메모리를 0으로 초기화할 때 유용합니다.
- realloc: 이미 할당된 메모리의 크기를 변경할 때 사용합니다.
이러한 함수들을 적절히 활용하면, 메모리 사용량을 최적화하고 동적인 데이터 구조(예: 연결 리스트, 동적 배열 등)를 구현할 수 있습니다. 다만, 할당된 메모리를 사용한 후에는 반드시 free를 호출하여 메모리 누수를 방지하는 것이 중요합니다.