자료구조(3) - 동적 할당과 원리

동적 할당을 하는 법과 원리 이해

Featured image

🔚 짧게 하는 복습

✅ 1. C의 기본 자료형과 기본 자료구조의 종류를 정확하게 알자.

✅ 2. C에서 지원하는 기본 자료구조의 특징과 메모리상 특징을 안다.

혹시 기억이 안 난다면, 다시 돌아가자


본격적인 자료구조 구현에 앞서, 먼저 배워야 할 것이 있다.

우리가 이때까지 어떤 것을 배울 때마다 메모리 구조, 저장방법을 배웠는데 앞으로는 우리가 직접 메모리를 다뤄야 할 일이 많기 때문이다.

그렇다고 걱정할 필요는 없다. 메모리 주소를 직접 접근해서 다루는 일은 아니기 때문이다.

마치 변수가 자료형을 받으면 메모리에 어떤 공간을 할당하듯이, 우리도 어떤 원하는 만큼의 공간을 요청하고 동적으로 할당받는 방법을 배울 것이다.


동적 할당이란?

우리는 지금까지 기본 자료형이나 자료구조를 변수를 이용해서 선언하는 방법을 배웠다.

그 과정 속에는 필요한 저장 공간 크기만큼을 메모리에 할당하고, 그 안에 값을 넣는 과정이 있었다.

오늘은 이를 직접 해보는 시간을 가져볼 것이다. 또한, 이렇게 직접 메모리를 할당하는 과정동적 할당이라고 한다.

int a = 3;

변수가 선언되는 순서대로 우리도 동적할당을 해볼 것이다.

  1. 시작주소가 랜덤하게 정해진다.

  2. int만큼의 공간이 할당된다.

  3. 그 공간에 3을 대입한다.

malloc 함수가 어떻게 동작하는지는 정확하게 몰라도, 우리가 컴파일러가 하던 일과 비슷한 일을 했다는 것을 느낄 수 있었다.


동적 할당의 원리

이번엔 아래의 예제를 동적 할당으로 바꿔보자.

int arr[5] = {1, 2, 3, 4, 5};

코드를 보면 이해하기 쉬울 것이다.

위에 int형의 sizeof를 이용해 할당한 것처럼, 여기서는 x5를 해서 5칸만큼 할당한 모습이다.

코드를 이해하는데도 문제가 없고, 논리에도 문제가 없을 것이다.

그런데 아래의 예제를 보자.

이게 뭐가 다른데?? 라고 생각할 사람들이 많을 텐데, 위의 코드는 전자와 어마어마한 차이가 있다.

배열의 최대 원소 수를 입력받는데 상수가 아니라 변수를 사용했다.

이는 원래 정적할당에서는 불가능했다..!

이것이 가능한 이유는 메모리 구조에 있다. 아래 그림을 다시 한번 보자.

원래 정적할당을 하면 변수든 배열이든 그 변수를 호출한 함수의 “stack” 영역에 저장이 되었다.(전역변수 제외)

하지만 동적할당을 하면 위의 그림의 heap 영역에 저장이 된다.

heap 영역은 stack 영역처럼 추가로 할당되고 해제도 되는 동적인 영역이다.

즉 heap 영역 안에서는 우리가 마음대로 동적 할당을 하고, 해제할 수도 있다는 것이다.

stack 영역의 특성은 스택 프레임의 크기를 컴파일 시점에서 정확하게 예측하기 어렵다는 점이다.

이러한 불확실성으로 인해, 스택 오버플로우를 예방하기 위해 충분한 배열의 공간을 사전에 상수로 지정한다.

반면, heap 영역은 프로그램이 실행된 후 동적으로 메모리를 할당하므로, 시작 시점에 공간 크기를 정확히 알 필요가 없다.


동적 할당이 필요한 이유

동적 할당이 필요한 이유는 정적할당과의 차이를 생각하면 된다.

정적할당의 가장 편한 점은 모든 과정을 컴파일러가 해준다는 점이다.

컴파일러가 직접 해줬기 때문에 우리가 할당된 영역을 수정할 수도 해제할 수도 없다.

한 번 할당되면 그 공간은 영원히 그 변수가 차지하게 된다.

하지만 동적 할당은 다르다. 메모리가 필요해서 추가로 할당할 수도 있고 더는 필요없다면 해제할 수도 있다.

위의 코드에서 전체 할당된 공간을 해제하는 방법은 쉽다.

free(arr);

이라고 하면 arr에 할당된 공간이 모두 해제된다.

중요한 점은 free를 한 공간에 다시 재할당한다고 해도, 그 값이 보존되는 보장이 없다는 것이다.

정적이든 동적이든 변수는 꼭 초기화하자.

다음은 메모리를 추가 할당하거나, 필요했던 공간 일부를 해제하는 재할당이다.

realloc함수는 원래 할당된 포인터, 다시 할당할 공간을 매개변수로 주면 다시 공간이 할당된 시작주소를 준다.

중요한 점은 원래 할당된 포인터에 재할당용 주소로 대입해야한다는 것이다..


📖 오늘의 핵심(다 알기 전까지는 넘어가지 말자❗)

✅ 1. 정적할당을 동적할당으로 구현할 수 있다.

✅ 2. 동적할당의 원리를 안다.

✅ 3. 동적할당을 이용하는 방법을 안다.

⚠️ 할당된 공간은 꼭 해제해주자. 메모리 누수 문제가 생긴다(읽어볼 거리 참조)

💣 과제, 없음

🔜 더 공부해보기,

  1. 읽어볼 거리(1) - 메모리 누수란?