코딩/C and C++

malloc calloc realloc의 차이점

이쿠우우 2022. 10. 3. 11:31
반응형

 

 

malloc calloc realloc의 차이점

 

malloc 

리턴 타입이 void* 즉 보이드 포인터다.
동적할당의 경우 어떤값을 리턴할지 명시해놓을 수 없기 때문에 void 로 리턴함.
할당된 메모리를 초기화하지 않기 때문에 쓰레기값이 그대로 들어가있다.
 

calloc

리턴 타입이 void* 즉 보이드 포인터다.
malloc 과는 다르게 할당된 메모리를 0으로 초기화 한다.
 

realloc

malloc 이나 calloc 을 통해 할당된 메모리의 공간을 더 늘리거나 줄이기 위해 사용된다.
무조건 필요한 만큼 메모리 공간이 있다는 가정하에 해야한다.
만약에 기존의 공간이 충분하지 않은경우를 예로 설명을 하자면 
malloc 으로 10의 공간을 할당한 후에 realloc 으로 5만큼의 공간을 늘리려는데
malloc 으로 할당한 주소의 11, ~ 15 주소값이 이미 사용중인 경우는
realloc 이 다른 15만큼의 여유가 있는 메모리 주소를 찾아서 해당 주소를 리턴한다.
기존에 저장되어 있던 값 또한 해당 주소값에 malloc 에서 저장한 값을 그대로 복사해서 가져오게 된다.
만일 10 이후 11 ~ 15 주소가 사용 가능하다면
기존 그대로 10주소 를 리턴하게 된다.
동적할당 시 가장 중요한건 역시 메모리 해제 free 이다.
 

 
 

realloc 의 위험성

 

1. 메모리 할당이 실패할 경우를 고려해야한다.

대표적인 문제로 realloc 메모리할당이 실패할 경우
NULL 이 반환되어 
기존의 메모리가 할당되어 있는 포인터를 잃어버립니다..
포인터만 잃어버리고 포인터가 가리키고 있던 배열은 
여전히 힙메모리에 남아서 메모리 누수 또한 발생
그래서 realloc 을 할때는 기존의 메모리 주소를 반드시 저장하고
실패 시 복구하는 프로세스가 함께 있어야합니다.
 
[예제 코드]
int * mem = malloc();
mem = realloc(); //실패 시 mem에는 null값 존재
그러므로 기존에 할당했던 mem이 free() 되지 않고 이제는 찾을 수 없는 곳으로 가버린 것이다.
당연히 이런 점은 메모리 누수로 남는다. 그리고 이런 코드가 (물론 그럴 일 없겠지만) 하나의 프로그램에서
화면을 Update하는 GUI쪽 함수라면 순식간에 메모리가 터져버린다.
 
그래서 realloc()을 할 때는 기존의 메모리 주소를 저장하고 실패 시 복구하는 프로세스가 함께 있어야 한다.
int * mem = malloc();
/*
   process - realloc 필요
*/
// 기존 메모리 주소 백업
int * mem_temp = mem;

// 메모리 재할당
mem = realloc();

// 복구 과정
if( mem == null ) {
    mem = mem_temp;
}
 
 
 

2. 함수내에서 realloc 주의점

동적할당 배열은 함주 매개변수로 넘긴 뒤
함수 내부에서 realloc 을 하게 되면 반드시 이중 포인터로 넘겨야한다.
 
예)
void fun_realloc(char *arr) 와 같이 단일 포인터를 파라미터로 넘기게 되면
함수내에서 할당된 위치가 변경되면 문제가 발생할 수 있습니다.
그렇기 때문에 void fun_realloc(char **arr)와 같이 
2중 포인터를 이용해서 접근해야합니다.
//틀리진 않지만 위험한 함수
void fun_realloc(char *arr) {
    arr = (char *)realloc(arr, 10 * sizeof(char));
    arr[5] = 'f';
    arr[6] = 'g';
    arr[7] = '\0';
}
 
//올바른 함수
void fun_realloc3(char **arr) {
    *arr = (char *)realloc(*arr, 10 * sizeof(char));
    arr[5] = 'f';
    arr[6] = 'g';
    arr[7] = '\0';
}
 
반응형