1. C언어의 malloc & free

우리가 C언어를 배울 때, malloc과 free란 녀석은 이미 만나본 적이 있습니다. malloc이란 함수는 '힙 영역에 메모리 공간을 할당할 수 있게 도와주는 함수'라고 말했었고, free 함수는 'malloc 함수 호출 시 할당되었던 메모리 공간을 전부 해제할 수 있게 도와주는 함수'라고 말한 적이 있었습니다. C언어 11강에서 보았던 예제를 다시 한번 보도록 하겠습니다.

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int studentNum, totalScore=0;
    int* studentScore;
    int i;
    
    printf("학생 수를 입력하세요: "); 
    scanf("%d", &studentNum);
    studentScore = (int *)malloc(sizeof(int) * studentNum);
    
    for(i=0; i<studentNum; i++) {
     printf("%d번 학생의 점수: ", i + 1);
     scanf("%d", &studentScore[i]);
     totalScore += studentScore[i];
    }
    
    printf("모든 학생의 평균: %d\n", totalScore / studentNum);
    free(studentScore);
    return 0;
}

결과:

학생 수를 입력하세요: 5

1번 학생의 점수: 1

2번 학생의 점수: 2

3번 학생의 점수: 3

4번 학생의 점수: 4

5번 학생의 점수: 5

모든 학생의 평균: 3

계속하려면 아무 키나 누르십시오 . . .


주목하셔야 할 부분은 12행의 malloc과 21행의 free 함수입니다. 이렇게 malloc 함수로 동적 할당하고, free로 그 동적 할당한 메모리를 해제해주었는데 이것을 C++에서는 new와 delete가 대신하게 되었습니다.


2. new & delete

그렇다면 C언어에서의 malloc과 delete가 어떻게 변했을까요? 먼저 new 연산자부터 살펴보도록 합시다.

...
// studentScore = (int *)malloc(sizeof(int) * studentNum);
studentScore = new int[studentNum];
...

감이 오시나요? new 연산자는 단일 객체를 동적 할당하고 싶을 때는 'new 자료형', 객체의 배열을 동적 할당 하고 싶을 때는 'new 자료형[길이]'와 같이 사용됩니다. 바로 아래와 같이 말이죠.

int* ptr1 = new int(3);
double* ptr2 = new double[3];
float* ptr3 = new float[10];

참고로, 1행은 길이 3의 객체의 배열을 할당하는 것이 아닙니다. 자세히 보시면 소괄호로 둘러싸여 있는데, 이는 new 연산자로 메모리 공간에 할당하고 그 값을 3으로 초기화 한다는 것입니다.

...
// free(studentScore);
delete []studentScore;
...

delete 연산자는 new 연산자로 할당된 객체의 메모리를 해제할 때 사용합니다. 'delete 포인터'와 같이 사용하며, 포인터는 할당을 해제할 객체를 가리키는 포인터를 의미합니다. 만약, 포인터가 객체 배열을 가리키고 있는 경우 포인터 앞에 빈 대괄호를 끼워 넣습니다. 'delete []포인터'와 같이 말이죠.

int* ptr1 = new int(3);
double* ptr2 = new double[3];
float* ptr3 = new float[10];
...
delete ptr1;
delete []ptr2;
delete []ptr3;

malloc과 free로 구현한 예제를 이번에는 new와 delete로 구현해보도록 하겠습니다.

#include <iostream>

using namespace std;
int main()
{
    int studentNum, totalScore=0;
    int* studentScore;
    int i;
    
    cout << "학생 수를 입력하세요: "; 
    cin >> studentNum;
    studentScore = new int[studentNum];
    
    for(i=0; i < studentNum; i++) {
     cout << i + 1 << "번 학생의 점수: ";
     cin >> studentScore[i];
     totalScore += studentScore[i];
    }
    
    cout << "모든 학생의 평균: " << totalScore / studentNum << endl;
	delete []studentScore;
    return 0;
}

결과:

학생 수를 입력하세요: 5

1번 학생의 점수: 1

2번 학생의 점수: 2

3번 학생의 점수: 3

4번 학생의 점수: 4

5번 학생의 점수: 5

모든 학생의 평균: 3

계속하려면 아무 키나 누르십시오 . . .

코드에서 12행을 살펴보시면 new 연산이 등장했습니다. studentNum에 5라는 값이 들어왔다고 가정하면, 길이가 5인 int형 배열을 동적 할당한 것입니다. 그리고 21행을 보시면 int형 배열이기 때문에 []studentScore로 해제해주어야만 합니다. 여기까지 이해하셨나요? 만약 이해가 되지 않으셨더라도, 배운 내용을 복습 겸 다시 살펴보면서 차근차근 나아가셔도 좋습니다.


  malloc/free와 new/delete는 어떤 차이가 있죠? 

malloc/free

new/delete

함수

연산자 

 초기값을 원하는 값으로 할당할 수 없음

할당과 초기화를 한꺼번에 할 수 있음 

필요한 크기는 바이트 단위로 지정해주어야 함

필요한 크기는 컴파일러에 의해 계산됨

할당된 메모리는 realloc을 통해 크기 변경이 가능

재할당이 불가능함 / STL의 컨테이너 라이브러리인 vector를 사용하는 것이 대안이 될 수 있음

할당 실패 시 NULL을 반환함 

할당 실패 시 std::bad_alloc 예외를 던짐

메모리 할당/해제에 초점이 맞추어져 있기 때문에 객체 생성/제거 시 생성자/소멸자 호출 안됨

객체 생성/제거 시 생성자/소멸자 호출


이번 강좌는 여기서 마치도록 하겠습니다. 수고하셨습니다.


다음 강좌에서는 구조체의 확장에 대해 배워보도록 하겠습니다.