C와 C++에서는 프로그램 실행 중에 필요한 만큼 메모리를 확보하는 동적 메모리 할당(Dynamic Memory Allocation) 기능을 제공합니다. 대표적인 방식이 바로 C의 malloc() 함수와 C++의 new 연산자입니다. 이 글에서는 두 방식의 문법, 동작 원리, 실제 예제를 통해 차이점을 자세히 살펴보겠습니다.
1. malloc() 함수란?
malloc() 함수는 요청한 크기만큼의 바이트를 메모리에 할당하고, 할당된 메모리 블록의 첫 번째 바이트를 가리키는 포인터를 반환합니다. 메모리 할당에 실패하면 널 포인터(NULL)를 반환하므로, 반드시 반환값을 확인하는 것이 안전한 코딩 습관입니다.
문법
pointer_name = (cast-type*) malloc(size);
- pointer_name: 포인터 변수에 부여하는 임의의 이름입니다.
- cast-type: malloc()이 할당한 메모리를 어떤 데이터 타입으로 변환(cast)할지 지정합니다.
- size: 할당할 메모리 크기를 바이트 단위로 지정합니다.
예제
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 4, i, *p, s = 0;
p = (int*) malloc(n * sizeof(int));
if(p == NULL) {
printf("\nError! memory not allocated.");
exit(0);
}
printf("\nEnter elements of array : ");
for(i = 0; i < n; ++i) {
scanf("%d", p + i);
s += *(p + i);
}
printf("\nSum : %d", s);
return 0;
}
실행 결과
Enter elements of array : 32 23 21 8 Sum : 84
위 프로그램에서는 네 개의 변수를 선언했으며, 그중 포인터 변수 *p가 malloc()으로 할당받은 메모리 주소를 저장합니다. 이후 배열 요소 4개를 입력받아 합계를 출력하는 구조입니다.
int n = 4, i, *p, s = 0;
p = (int*) malloc(n * sizeof(int));
if(p == NULL) {
printf("\nError! memory not allocated.");
exit(0);
}
printf("\nEnter elements of array : ");
for(i = 0; i < n; ++i) {
scanf("%d", p + i);
s += *(p + i);
}
printf("\nSum : %d", s);
여기서 핵심 포인트는 다음과 같습니다.
n * sizeof(int): 정수형 변수 4개가 들어갈 만큼의 크기를 바이트 단위로 계산합니다.(int*): void 포인터로 반환되는 값을 int 포인터로 명시적으로 형변환합니다.NULL검사: 할당 실패 여부를 확인해야 런타임 오류를 예방할 수 있습니다.
2. new 연산자란?
C++의 new 연산자는 힙(heap) 영역에 메모리 할당을 요청합니다. 충분한 메모리가 남아 있다면 해당 메모리를 초기화한 후 포인터 변수에 저장하고 그 주소를 반환합니다. malloc()과 달리 객체 생성 시 생성자를 자동으로 호출한다는 점이 큰 특징입니다.
기본 문법
pointer_variable = new datatype;
초기화를 함께 수행하는 문법
pointer_variable = new datatype(value);
메모리 블록(배열)을 할당하는 문법
pointer_variable = new datatype[size];
예제
#include <iostream>
using namespace std;
int main () {
int *ptr1 = NULL;
ptr1 = new int;
float *ptr2 = new float(223.324);
int *ptr3 = new int[28];
*ptr1 = 28;
cout << "Value of pointer variable 1 : " << *ptr1 << endl;
cout << "Value of pointer variable 2 : " << *ptr2 << endl;
if (!ptr3)
cout << "Allocation of memory failed\n";
else {
for (int i = 10; i < 15; i++)
ptr3[i] = i+1;
cout << "Value to store in block of memory: ";
for (int i = 10; i < 15; i++)
cout << ptr3[i] << " ";
}
return 0;
}
실행 결과
Value of pointer variable 1 : 28 Value of pointer variable 2 : 223.324 Value to store in block of memory: 11 12 13 14 15
위 프로그램에서는 세 개의 포인터 변수 ptr1, ptr2, ptr3를 선언했습니다. ptr1과 ptr2는 new를 사용해 값을 초기화하며, ptr3는 new로 할당한 메모리 블록(정수 28개 크기의 배열)의 시작 주소를 저장합니다.
ptr1 = new int; float *ptr2 = new float(223.324); int *ptr3 = new int[28]; *ptr1 = 28;
3. malloc()과 new의 주요 차이점 정리
두 방식의 특징을 한눈에 비교할 수 있도록 정리하면 다음과 같습니다.
| 구분 | malloc() | new |
|---|---|---|
| 종류 | C 표준 라이브러리 함수 | C++ 연산자 |
| 반환 타입 | void* (명시적 형변환 필요) | 해당 타입의 포인터 (형변환 불필요) |
| 초기화 | 불가능 (쓰레기 값 유지) | 가능 (생성자 호출) |
| 생성자/소멸자 호출 | 호출하지 않음 | 자동으로 호출 |
| 할당 실패 시 | NULL 반환 | bad_alloc 예외 발생 |
| 메모리 해제 | free() | delete / delete[] |
결론적으로, C 언어 환경이나 저수준 제어가 필요한 경우에는 malloc()과 free() 조합을, C++에서는 생성자·초기화·타입 안전성 측면에서 유리한 new와 delete 조합을 사용하는 것이 좋습니다. C++11 이상에서는 더욱 안전한 스마트 포인터(std::unique_ptr, std::shared_ptr) 활용도 고려해 보세요.