63.3 이중 포인터 매개변수 사용하기

지금까지 함수에서 포인터 매개변수를 이용해서 정수, 실수 등의 값을 가져왔습니다. 그러면 일반적인 값 대신 포인터(메모리 주소)를 얻어오려면 어떻게 해야 할까요?

먼저 함수에 포인터를 넘겨준 뒤 메모리를 할당해보겠습니다. 다음 내용을 소스 코드 편집 창에 입력한 뒤 F5 키를 눌러서 디버깅 모드로 실행해보세요.

parameter_single_pointer.c

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

void allocMemory(void *ptr, int size)    // 반환값 없음, void 포인터 매개변수 지정
{
    ptr = malloc(size);    // ptr은 allocMemory를 벗어나면 사용할 수 없음
}

int main()
{
    long long *numPtr = NULL;

    // numPtr과 할당할 크기를 넣어줌 
    allocMemory(numPtr, sizeof(long long));

    *numPtr = 10;    // 메모리가 할당되지 않았으므로 실행 에러
    printf("%lld\n", *numPtr);

    free(numPtr);

    return 0;
}

실행 결과

0xC0000005: 0x00000000 위치를 기록하는 동안 액세스 위반이 발생했습니다.

잘 될 것 같지만 실행을 해보면 에러가 발생합니다. 왜 그럴까요? void allocMemory(void *ptr, int size)와 같이 매개변수를 void 포인터로 지정한 뒤 ptr에 메모리를 할당했습니다. 하지만 ptr에 메모리를 할당해봐야 allocMemory 함수를 벗어나면 사용할 수가 없습니다. 결국 메모리 누수가 발생하지요.

void allocMemory(void *ptr, int size)    // 반환값 없음, void 포인터 매개변수 지정
{
    ptr = malloc(size);    // ptr은 allocMemory를 벗어나면 사용할 수 없음
}

이번에는 이중 포인터를 사용하여 함수 안에서 메모리를 할당한 뒤 가져와보겠습니다.

parameter_double_pointer.c

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

void allocMemory(void **ptr, int size)    // 반환값 없음, void 이중 포인터 매개변수 지정
{
    *ptr = malloc(size);    // void **ptr을 역참조하여 void *ptr에 메모리 할당
}

int main()
{
    long long *numPtr;

    // 단일 포인터 long long *numPtr의 메모리 주소는 long long **와 같음, 할당할 크기도 넣음 
    allocMemory((void**)&numPtr, sizeof(long long));

    *numPtr = 10;
    printf("%lld\n", *numPtr);

    free(numPtr);    // 동적 메모리 해제

    return 0;
}

실행 결과

10

allocMemory 함수를 만들 때 void allocMemory(void **ptr, int size)와 같이 void 이중 포인터 ptr을 받도록 만듭니다. 물론 할당할 메모리 크기도 알아야 하므로 size도 함께 받습니다.

함수 안에서는 매개변수 void **ptr를 역참조하여 void *ptr이 되도록 만든 뒤 malloc 함수로 메모리를 할당합니다.

void allocMemory(void **ptr, int size)    // 반환값 없음, void 이중 포인터 매개변수 지정
{
    *ptr = malloc(size);    // void **ptr을 역참조하여 void *ptr에 메모리 할당
}

이제 long long *numPtr;와 같은 단일 포인터를 선언한 뒤 numPtr의 메모리 주소를 구해서 allocMemory 함수에 넣어줍니다. 즉, long long *numPtr;의 메모리 주소는 long long **과 같으므로 매개변수 void **ptr로 받을 수 있습니다.

long long *numPtr;

// 단일 포인터 long long *numPtr의 메모리 주소는 long long **와 같음, 할당할 크기도 넣음
allocMemory((void**)&numPtr, sizeof(long long));

*numPtr = 10;
printf("%lld\n", *numPtr);

free(numPtr);    // 동적 메모리 해제

다음과 같이 매개변수 void **ptr을 역참조하여 실제로는 numPtr에 메모리를 할당하게 됩니다.

그림 63‑5 이중 포인터 매개변수