240201_동적 메모리 할당

추성결·2024년 2월 1일
0

참조: https://www.youtube.com/watch?v=bEkAckPDHkM
참조: https://www.youtube.com/watch?v=_1PiJAjB7Io
참조: https://ko.wikipedia.org/wiki/%EB%8F%99%EC%A0%81_%EB%A9%94%EB%AA%A8%EB%A6%AC_%ED%95%A0%EB%8B%B9
참조: https://velog.io/@saint6839/C%EC%96%B8%EC%96%B4-%EB%8F%99%EC%A0%81-%EB%A9%94%EB%AA%A8%EB%A6%AC-%ED%95%A0%EB%8B%B9-%EA%B0%9C%EB%85%90-%EC%9E%A1%EA%B8%B0

동적 메모리 할당이란

  • 컴파일 시점에 메모리 공간을 확보하는 정적 메모리 할당과는 달리, 런타임시에 사용할 메모리를 할당하는 것을 뜻한다.

  • Stack영역에 메모리가 위치해 있다면, 함수가 종료되는 등의 이유로 다 사용하면 메모리가 자동으로 해제되는데, 동적 할당을 사용하면 Heap영역에 메모리 할당을 하여 프로그래머가 수동으로 해제를 하지 않을 시, 해당 메모리는 사라지지 않고 남게된다.

  • 실행 시간에 크기가 결정되는 동적 배열 및 리스트와 같은 경우는 heap을 사용하는 것이 보다 공간을 효율적으로 활용할 수 있다.(Heap, Stack, Data영역의 자세한 내용은 여기서 확인하자.)

동적 메모리 할당 방법

  • malloc과 calloc등으로 동적 할당을 해주는 함수로 구현한다.
int *arr = (int *)malloc(sizeof(int) * 10)
int *arr = (int *)calloc(10, sizeof(int))

malloc의 경우, int타입 크기의 10배 만큼(즉, 40)의 메모리를 할당해준다. malloc은 메모리만 할당해주고 초기화를 해주지 않는다.

calloc의 경우, 두번째 파라미터 크기에(int의 크기에) 첫번째 파라미터(10)만큼 할당해준다. calloc은 메모리 할당과 초기화(0으로 초기화)를 해준다.

  • malloc 함수로 예시를 들면
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	int *pi;
    pi = (int *)malloc(sizeof(int) * 5);
    
    if(pi == NULL)
    {
    	printf("동적 메모리 할당에 실패했습니다.");
        exit(1);
    }
    
    *pi = 100;
    
    printf("%d\n", *pi)         // 출력 결과: pi = 100
    
    free(pi)                    // 동적 메모리 사용한 후에는 해당 메모리 해제 과정 필수!
}

메모리 누수의 예

int *a = malloc(5); // 5byte 메모리 공간 선언
int *b = malloc(10); // 10byte 메모리 공간 선언

b = a; // b가 a의 주소를 가리킴

free(a); // a할당 해제
free(b); // b도 a의 주소를 가리키므로, a할당 해제

메모리 재할당

  • 메모리 재할당은 realloc 함수를 사용해 메모리 공간 재할당이 가능하다.
void *realloc(void *ptr, size_t size);

주의할점

  • realloc은 크기가 0이거나 해당 크기의 바이트만큼 할당할 수 없다면, ptr은 그대로 남겨둔채 NULL을 반환한다.
void ReallocExample()
{
   char* buffer = (char*)malloc(4);
   buffer = (char*)realloc(buffer, 8);
}
  • 만일 위의 경우에서 기존 ptr이 사라지면서 힙 영역에 할당된 메모리 주소를 잃어버리게 된다. 따라서 메모리 누수가 생기고, realloc에 실패하게 되면 buffer는 기존 주소를 잃는다.

메모리 백업 realloc 코드

void ReallocExample()
{
   // malloc 조건문은 생략
   char* buffer = (char*)malloc(4);
   
   // buffer 백업
   char* backupBuffer = buffer;
   
   if( NULL == (buffer = (char*)realloc(buffer, 8)) )
   {
      // 종료 시
      free(backupBuffer);
      fprintf(stderr, "Memory allocation is failed");
      exit(1);
      
      // 프로그램 계속 진행할 시 주소 복구
      // buffer = backupBuffer;
   }
   
   // Do something..
}

동적 메모리 활용

  • 동적 메모리를 사용하여 구조체 작성
#include <stdio.h>
#include <stdlib.h>

struct Book
{
    int number;
    char title[100];
};

void ShowBook(struct Book *p, int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
        printf("번호 %d : %s\n", (p+i) -> number, (p+i) -> title);
    }
}

int main(void)
{
    struct Book *p;
    p = (struct Book *)malloc(2 * sizeof(struct Book));
    if(p == NULL)
    {
        printf("동적 메모리 할당에 실패했습니다.\n");
        exit(1);
    }

    p->number = 1;
    strcpy(p -> title, "C Programming");

    (p + 1) -> number = 2;
    strcpy((p + 1)-> title, "Data Structure");

    ShowBook(p, 2);
    free(p);
    return 0;
}
  • 2차원 배열
int main(void)
{
    int i, x, y;

    // 2차원 배열을 만들기 위해 int가 들어갈 수 있는 인트형 포인트 크기의 메모리를 할당해준다.
    int** pptr = (int**)malloc(sizeof(int*) * 8);

    // 각 할당된 메모리에 다시 int크기의 메모리를 할당해준다.
    for(i = 0; i < 8; i++)
    {
        *(pptr + i) = (int *)malloc(sizeof(int) * 6);
    }

    // 각 요소에 0~47까지의 정수를 넣어준다.
    for(x = 0; x < 8; x++)
    {
        for(y = 0; y < 6; y++)
        {
            *(*(pptr + x) + y) = 6 * x + y;
        }
    }

    // 하나씩 출력
    for(x = 0; x < 8; x++)
    {
        for(y = 0; y < 6; y++)
        {
            printf("%3d", *(*(pptr + x) + y));
        }
        printf("\n");
    }

    // 메모리 할당 해제
    for(x = 0; x < 8; x++)
    {
        free(*(pptr + x));
    }

    return 0;
}

0개의 댓글