본문 바로가기
[R&D] 프로그래밍/C, C++

[C/C++] 메모리 동적할당 2 (realloc, calloc)

by Geuni 2022. 8. 3. 06:00
728x90
반응형

지난 포스팅에서 메모리 동적 할당에 대해 설명하고 있습니다.

realloc과 calloc은 그의 연장선입니다. 아래 포스팅을 참고해주세요.

[C/C++] 메모리 동적할당 및 해제 (malloc, free) 사용법 (tistory.com)

 

[C/C++] 메모리 동적할당 및 해제 (malloc, free) 사용법

메모리 동적할당이란?  프로그래밍을 할 때 사용하는 변수들은 모두 메모리에 저장되어 사용됩니다. 이중 전역 변수/정적 변수는 프로그램의 시작과 종료 시점에, 지역 변수/매개 변수는 함수

geuninote.tistory.com


calloc

우선 calloc()의 함수 원형은 아래와 같습니다.

#include <stdlib.h>

void *calloc(size_t number, size_t size);
number : 할당받을 메모리 요소의 개수를 말합니다.
size : 각 요소의 크기를 말합니다. (자료형의 크기, byte 단위)

calloc()malloc()와 마찬가지로 원하는 크기의 메모리를 동적으로 할당받는 역할을 합니다.

하지만 차이점이 있습니다.

  1. 할당받을 byte의 크기만큼 한 번에 받는 게 아닌 요소(자료형)의 크기(byte)와 개수로 나누어 매개변수를 받습니다.
  2. 메모리 할당과 동시에 값을 0으로 초기화합니다.

위 두 가지의 차이를 빼면 malloc과 동일하다고 생각하시면 됩니다.

예제)

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *pMint;
    int *pCint;

    int count = 5;

    pMint = (int *)malloc(sizeof(int) * count);
    pCint = (int *)calloc(count, sizeof(int));

    for(int i=0; i<count; i++)
    {
        printf("pMint[%d] = %d / pCint[%d] = %d\n", i, pMint[i], i, pCint[i]);
    }

    free(pMint);
    free(pCint);
    
    return 0;
}

pMint[0] = -1163005939 / pCint[0] = 0
pMint[1] = -1163005939 / pCint[1] = 0
pMint[2] = -1163005939 / pCint[2] = 0
pMint[3] = -1163005939 / pCint[3] = 0
pMint[4] = -1163005939 / pCint[4] = 0

위 예제에서 볼 수 있는 것처럼 malloc()은 요소의 크기와 개수의 곱으로, calloc()은 요소의 크기와 개수를 별도로 입력하고 있습니다.

또한 차이점 두 번째인 calloc()은 메모리를 0으로 초기화한다는 것도 결과 로그를 통해 알 수 있습니다. malloc()은 garbage data가 들어있음을 확인할 수 있습니다.


realloc

realloc의 함수 원형은 아래와 같습니다.

#include <stdlib.h>

void *realloc(void *ptr, size_t size);
*ptr : 이미 동적 할당을 받은 메모리의 주소(ptr)를 말합니다.
size : 새로 할당받을 크기를 입력합니다.

realloc()은 함수의 이름에서 보이듯 할당받은 메모리를 원하는 사이즈로 다시(re) 할당받는 기능을 합니다.

여기서 size는 malloc()를 사용할 때처럼 할당받을 메모리의 크기 전체를 입력하면 됩니다.

 

예제)

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

int main(void)
{
    int* pMint;
    int* pRint;
    int mallocSize, reallocSize;

    int count = 5;

    pMint = (int*)malloc(sizeof(int) * count);
    mallocSize = _msize(pMint);

    pRint = (int*)realloc(pMint, (count + 2) * sizeof(int));
    reallocSize = _msize(pRint);

    printf("malloc size : %d / realloc size : %d\n", mallocSize, reallocSize);

    if((pMint != NULL) && (pRint != NULL))
    {
        printf("malloc : 0x%p / realloc : 0x%p\n", pMint, pRint);
        for (int i = 0; i < count + 2; i++)
        {
            printf("pRint[%d] = %d\n", i, pRint[i]);
        }
    }

    free(pRint);
    
    return 0;
}

malloc size : 20 / realloc size : 28
malloc : 0x00B12838 / realloc : 0x00B12838
pRint[0] = 11610576
pRint[1] = 11600064
pRint[2] = 754974765
pRint[3] = 875
pRint[4] = 11610576
pRint[5] = 11600064
pRint[6] = 721420331

출력 결과를 봤을 때 몇 가지 짚고 넘어가야 할 게 있습니다.

 

1. realloc를 통해 다시 할당받은 메모리는 주소 값이 이전과 같을 수도 다를 수도 있습니다.

 그렇기 때문에 이전에 사용하던 주소와 값은 무의미해집니다.

2. malloc과 마찬가지로 값을 초기화하지 않고 할당합니다.

3. 예제에서는 크기를 더 키웠지만 반대로 줄이는 것도 가능합니다.

 

참고)
참고로 위에서 사용된 _msize()라는 함수는 할당받은 메모리의 크기를 확인할 수 있습니다.
<malloc.h>를 추가해 사용이 가능합니다.

 

예제는 malloc()과 realloc()의 차이를 설명하기 위해서 변수를 다르게 사용했지만 사실 아래와 같은 형태로 많이 사용합니다.

pMint = (int*)realloc(pMint, (count + 2) * sizeof(int));

이처럼 사용하던 포인터 변수에 다시 할당을 받는 것인데요. 이는 단순히 스타일이긴 하지만 무의미하게 변수를 많이 만들어 쓰지 않기 때문에 가독성 및 운용 방법면에서 좋습니다.

하지만 이처럼 쓸 때는 조심해야 할 게 있습니다. 만약 realloc 하지 못해 에러 값, 즉 'NULL'을 반환받게 된다면 이전에 할당받은 메모리의 주소를 잃기 때문에 free 하지 못해 '메모리 누수'가 발생할 수 있기 때문입니다.

 

참고) 메모리 누수란?
메모리 누수는 영어로 menory leak이라고 하는데, 프로그램 동작중에 더 이상 사용되지 않는(필요 없는) 메모리가 계속 점유하고 있는 현상으로 메모리 누수가 증가하면 메모리가 낭비되는 영역이 늘어나고 사용 가능한 메모리 공간이 그만큼 없어진다는 의미가 됩니다.
728x90
반응형

댓글