본문 바로가기
C

메모리 동적 할당

by oncerun 2023. 5. 2.
반응형

 

 

지금까지 정적할당만 하였다. 

 

전역변수와 static 변수를 담는 데이터 영역과 지역변수와 매개변수를 담는 스택영역에 대해서만 메모리를 할당하였다. 

 

데이터 영역은 프로그램의 생명주기와 동일하게 할당되고 해제된다.  스택영역은 함수 호출과 종료의 라이프 사이클에 의해 스택영역에 할당되고 종료된다. 

 

즉 이는 프로그램 작성 시점에 기억공간의 할당공간을 어림잡을 수 있다. 

 

정적할당은 쉽게 기억공간을 사용할 수 있고, 에러의 발생 확률을 줄일 수 있다. 하지만 사용하게 될 기억 공간의 크기를 정확히 알지 못하거나, 사용되는 자료의 크기가 각각 차이가 심하다면 우리는 기억공간을 낭비하게 된다.

 

그렇다면 동적 할당은 왜 하는 걸까? 

 

프로그램 실행 중에 메모리 공간을 사용해야 할 일이 반드시 발생한다. 이 경우 동적으로 저장공간을 할당하고 사용해야 하기 때문인데, 생각보다 이러한 일이 자주 발생된다. 

 

 

순서는 다음과 같다.

 

기억공간을 동적으로 할당 받을 변수를 포인터를 이용하여 선언한다.

 

이후 malloc() 함수 등을 이용하여 기억공간을 동적으로 할당한다.

 

기억공간의 사용이  끝나면 free() 함수를 이용하여 기억공간을 해제한다.

 

보통 다음과 같은 함수를 이용한다. malloc, calloc, realloc, free 

 

 

malloc 함수는 인자로 할당 받고자 하는 기억 공간의 크기를 byte 단위로 전달한다. 힙 영역에 그 크기만큼 기억 공간을 할당하고 할당한 기억 공간의 첫 번째 주소를 반환해 준다. 

 

void* 로 명시되어 어떤 형으로든 형 변환이 가능하다

 

기억공간의 초기화를 위해서는 memset() 사용해야 한다.

 

calloc은 초기화가 되어 있다. 

 

이렇게 힙 영역에 할당된 공간은 프로그램이 종료될 때까지 유지된다.

 

그래서 할당된 기억 공간을 해제하지 않으면 기억 공간의 부족 현상이 발생되어 명시적인 반납이 필요하다.

 

int main() {

    int *a;

    a = (int *) malloc(sizeof(int) );

    if (a == NULL){
        puts("기억 공간 할당 실패");
        exit(1);
    }

    *a = 10;

    printf("힙에 저장된 변수 %d\n", *a);

    free(a);

    return 0;
}

 

 

calloc은 다음과 같이 사용한다.

int main() {

    int i;

    int *a;

    a = (int *) calloc(5, sizeof(int));

    for (i = 0; i < 5; i++) {
        printf("%d\n", a[i]);
    }

    free(a);


    return 0;
}

 

전부 0으로 초기화되어 있다.

 

realloc은 이미 할당 받은 기억 공간의 크기를 변경해야 할 필요가 있을 경우에 사용한다.

 

 

int main() {

    int i;

    int *a;

    a = (int *) calloc(5, sizeof(int));

    if (a == NULL) {
        printf("Error");
        return 1;
    }

    a = (int *) realloc(a, 10 * sizeof(int));

    for (i = 0; i < 10; i++) {
        printf("%d ", a[i]);
    }

    free(a);




    return 0;
}

Clang-Tidy의 이 경고는 코드에 메모리 누수 위험이 있음을 나타냅니다.

동적으로 할당된 버퍼의 크기를 조정하기 위해 realloc을 호출하면 실패하고 NULL 포인터를 반환할 가능성이 있습니다. 이런 일이 발생하면 원래 버퍼가 계속 할당되고 포인터가 손실되어 메모리 누수가 발생합니다.

이 문제를 피하려면 포인터에 할당하기 전에 항상 realloc의 반환 값을 확인해야 합니다. NULL을 반환하는 경우 오류를 적절하게 처리해야 하며 필요한 경우 원래 버퍼를 해제하는 작업이 포함될 수 있습니다.

예를 들어 다음과 같이 NULL 검사를 포함하도록 코드를 수정할 수 있습니다.

void* newBuffer = realloc(buffer, newSize);
if (newBuffer == NULL) {
    // handle the error
} else {
    buffer = newBuffer;
}


이렇게 하면 코드가 메모리 할당 오류를 올바르게 처리하고 잠재적인 메모리 누수를 방지할 수 있습니다.

 

 

 

반응형

'C' 카테고리의 다른 글

구조체  (0) 2023.05.01
포인터와 배열.  (0) 2023.04.29
포인터  (0) 2023.04.29
C언어에서 배열을 어떻게 다룰까?  (0) 2023.04.17
입력 및 출력 프로그램  (0) 2023.04.16

댓글