82. 동적 메모리 할당 함수

C언어에서는 데이터를 관리하기 위해 메모리를 할당받는 방법으로 변수 선언을 제공하고 있어요.
그런데 변수 선언으로 메모리를 할당받는 것은 컴파일러 시점에 할당할 메모리 크기를 결정해요.
물론 실제 메모리를 할당하는 시점은 프로그램이 실행 중에 할당하지만 할당할 크기를 결정하는 것은 컴파일 시점이예요.

그런데 프로그래밍하다 보면 할당할 메모리 크기를 컴파일 시점이 아닌 프로그램 실행 중에 결정할 때도 있어요.
학생 관리 프로그램에서 최대 관리할 학생 수를 최종 사용자가 결정할 수 있다면 개발자가 정하는 것보다 훨씬 유연하겠죠.

C언어에서는 표준 라이브러리 함수로 동적 메모리 할당 관련 함수를 제공하고 있어요.

void *malloc(size_t size);
void *calloc(size_t count,size_t size);
void *realloc(void *base,size_t nsize);
void free(void *base);

동적 메모리 할당 관련 함수를 사용하려면 stdlib.h 파일을 추가하세요.
메모리를 동적으로 할당할 때는 목적에 따라 malloc, calloc, realloc 함수를 사용할 수 있어요.
그리고 동적 메모리 할당을 요청하면 힙 메모리에 할당한답니다.
이렇게 동적으로 할당한 메모리는 free 함수로 해제할 수 있어요.

주의할 점은 free 함수는 동적으로 할당한 메모리만 해제할 수 있고 부분적으로 해제할 수는 없어요.
만약 동적으로 할당한 메모리를 해제하지 않으면 메모리 누수가 발생해요.

malloc, calloc, realloc 함수의 반환 형식을 보면 모두 void *죠.
여기에서 void *는 원소 형식을 정하지 않은 포인터를 말해요.

void 포인터 변수를 선언하면 원소 형식은 결정하지 않고 메모리 주소를 값으로 갖는 메모리 4바이트를 할당해요.
그리고 원소 형식에 관계없이 포인터를 받을 수 있어요.
◈ void 포인터 변수에 다른 원소 형식의 포인터 변수를 대입하여 주소를 출력한 예

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    char name[10+1]="Hello";
    void *vp = 0;
    vp = arr; //int 형을 원소로 하는 포인터를 대입
    printf("vp: %p arr: %p \n", vp, arr);
    vp = name;  //char 형을 원소로 하는 포인터를 대입
    printf("vp: %p name: %p \n", vp, name);
    return 0;
}

◈ 실행 결과

vp: 004DFAC0 arr: 004DFAC0
vp: 004DFAAC name: 004DFAAC

하지만 원소 형식을 결정하지 않았서 간접 연산이나 인덱스 연산으로 원소에 접근하여 사용할 수가 없어요.

int arr[10] = {1,2,3,4,5,6,7,8,9, 10};
void *vp = 0;

vp = arr; //int 형을 원소로 하는 포인터를 대입, 가능한 표현
*vp = 0; //void 포인터를 간접 연산의 피연산자로 사용할 수 없음
vp[0] = 0; //void 포인터를 인덱스 연산의 피연자로 사용할 수 없음