malloc vs calloc: 핵심 차이점과 실전 예제로 완벽 이해
동적 메모리 할당이란?
동적 메모리 할당을 사용하면 프로그램이 런타임에 메모리를 요청하고 해제할 수 있습니다. C언어에서 표준 라이브러리는 이 목적을 위해 네 가지 주요 함수를 제공합니다: malloc(), calloc(), realloc(), free() — 모두 stdlib.h에 선언되어 있습니다.
malloc(): 단일 메모리 블록 할당
malloc()(memory allocation의 줄임말)은 연속된 바이트 블록을 예약하고 첫 번째 바이트에 대한 포인터를 반환합니다. 새로 할당된 블록의 내용은 불확정(indeterminate) 상태로, 해당 메모리 위치에 있던 비트 패턴이 그대로 남아 있습니다.
일반적인 사용법:
int *p = (int *)malloc(n * sizeof(int));
요청이 실패하면
malloc()은
NULL을 반환합니다.
calloc(): 다중 제로 초기화 블록 할당
calloc()(contiguous allocation의 줄임말)은 두 개의 인자를 받습니다: 요소의 개수와 각 요소의 크기. 모든 요소에 대한 메모리를 할당하고 모든 바이트를 자동으로 0으로 설정하므로, 깨끗한 초기 상태가 필요한 배열이나 구조체에 이상적입니다.
일반적인 사용법:
int *p = (int *)calloc(n, sizeof(int));
malloc()과 마찬가지로 할당 실패 시
NULL을 반환합니다.
각 함수 사용 시기
- malloc() — 단일 블록이 필요하고 메모리를 직접 초기화할 계획일 때 사용. 제로화 단계를 건너뛰므로 약간 더 빠릅니다.
- calloc() — 0으로 초기화된 상태로 시작해야 하는 배열이나 구조체가 필요할 때 사용. 자동 초기화로 가비지 값 사용으로 인한 버그를 방지합니다.
문법 개요
malloc()
void *malloc(size_t size);
calloc()
void *calloc(size_t num, size_t size);
실전 코드 예제
예제 1: malloc()으로 15개 정수 저장
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *ptr = malloc(15 * sizeof(*ptr));
if (!ptr) {
perror("malloc failed");
return EXIT_FAILURE;
}
ptr[5] = 480; // 6번째 요소 (0-기반 인덱스)
printf("6번째 정수의 값은 %d\n", ptr[5]);
free(ptr);
return EXIT_SUCCESS;
}
출력: 6번째 정수의 값은 480
예제 2: calloc()으로 합계 계산
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *ptr = calloc(10, sizeof(int));
if (!ptr) {
perror("calloc failed");
return EXIT_FAILURE;
}
int sum = 0;
for (int i = 0; i < 10; ++i) {
ptr[i] = i; // 초기화는 중복이지만 명확성을 위해 표시
sum += ptr[i];
}
printf("합계 = %d\n", sum);
free(ptr);
return EXIT_SUCCESS;
}
출력: 합계 = 45
한눈에 보는 비교
| 특징 | malloc() | calloc() |
| 매개변수 개수 | 1개 (크기) | 2개 (개수, 크기) |
| 할당 후 메모리 상태 | 초기화 안 됨 (가비지 값) | 제로 초기화됨 |
| 일반적 용도 | 단일 블록, 수동 초기화 | 깨끗한 시작이 필요한 배열/구조체 |
| 성능 | 더 빠름 (제로화 없음) | 더 느림 (제로화 오버헤드) |
| 안전성 | 가비지 값 사용 위험 높음 | 자동 제로화로 위험 낮음 |
| 실패 시 반환값 | NULL | NULL |
| 표준 헤더 | stdlib.h | stdlib.h |
핵심 요약
- 직접 초기화할 단일 블록이 필요하고 약간의 성능 이득을 원하면
malloc() 사용.
- 배열이나 구조체에 특히 제로 초기화된 메모리가 필요하면
calloc() 사용하여 미묘한 버그 방지.
- 두 함수 모두 실패 시
NULL 반환, 역참조 전 항상 확인 필수.
free()로 할당된 메모리 해제하여 메모리 누수 방지.