malloc과 calloc과 같은 동적 메모리 할당을 사용하는 이유는 프로그램 실행 중에 변화하는 변수나 데이터의 크기를 유연하게 관리할 수 있기 때문이다. 또한 한정된 메모리를 유동적으로 할당하고 해제할 수 있기 때문이다.
이를 자세히 알아보자.
1. 코드 실행 중 메모리가 변화?
코드 실행 중 메모리 크기가 변동하는 경우는 프로그램을 짜는 도중에 변수의 크기를 정할 수 없다.
예를 들어 배열의 크기가 사용자가 제시한 크기만큼 실시간으로 할당받아야 한다면 프로그램을 짜는 도중에는 배열의 크기를 정할 수 없다.
그렇기 때문에 사용자에 입력에 따라 변수의 데이터 크기를 다르게 받을 방법 중 하나가 동적할당인 것이다.
malloc을 사용해 동적할당을 수행한 모습이다. 이를 통해 사용자가 원하는 크기만큼 유연하게 메모리의 크기를 정할 수 있다.
2. 그냥 처음부터 메모리의 크기를 크게 받으면 되지 않나?
함수 내에서 메모리의 크기가 큰 변수를 선언하면 Stack에 저장되며, Stack은 제한된 크기에 메모리 공간을 가지고 있다. 그렇기에 큰 배열이나 구조체를 Stack에 할당하면 Stack의 크기를 초과하여 Stack Overflow가 발생할 수 있다.
또한 배열의 크기를 고정하면 사용자가 실제로 필요로 하는 크기와 맞지 않을 경우 불필요한 메모리 공간이 낭비될 수 있다. 예를 들면 100기의 요소를 정적할당 했으나 실제로는 20개만 사용하는 경우 80개의 공간이 낭비된다.
정적 할당과 동적 할당의 코드상 차이를 보여준다.
3. C 언어에서 동적 메모리를 할당하는 두 가지 함수! malloc, calloc!
3.1. malloc(Memory Allocation)
malloc 함수는 C 언어에서 동적 메모리를 할당하는 데 사용되는 표준 라이브러리 함수이다. 이 함수는 프로그램이 실행되는 동안 필요에 따라 메모리를 동적으로 할당할 수 있게 해준다.
- malloc의 선언
malloc 함수는 C 표준 라이브러리의 stdlib.h 헤더 파일에 다음과 같이 선언되어 있다.
- malloc의 단순화된 구현
malloc 함수의 기능은 메모리가 부족한 경우 NULL을 return하고, 메모리가 부족하지 않다면 메모리를 할당할 크기만큼 offset을 업데이트하여 포인터를 반환한다. 이 때 malloc 함수가 void* 형식의 포인터를 반환한다.
- malloc 사용 예시
- 포인터 변수로 선언(int* arr): 저장할 데이터의 주소를 가리키는 포인터 변수를 생성한다.
arr은 동적으로 할당된 메모리 블록의 시작 주소를 가리킨다. malloc이 반환하는 주소는 arr이 가리키는 메모리의 시작점을 나타내며, arr은 그 주소에 직접 접근할 수 있다.
메모리 블록은 5개의 int형 데이터를 저장하는 장소이다. 이 장소는 메모리에서 물리적으로 할당된 공간으로 arr 포인터가 가리키는 주소에 데이터가 저장된다. 예를 들어 arr[0], arr[1], ... , arr[4]는 각각 할당된 메모리 공간의 위치에 저장된 값이다.
- malloc의 반환 값
malloc 함수는 void* 타입의 포인터를 반환한다. 그렇기 때문에 선언한 변수에 맞춰 자료형을 casting해줘야 한다. 위 코드에서는 int* 타입으로 casting하였다.
- 함수 인자
malloc의 인자는 할당할 메모리의 크기이다. 여기서 단위는 Byte 단위이므로 sizeof() 함수를 사용하여 자료형이 몇 Byte인지 계산해주고 그 수에 개수만큼 곱하는 걸 확인할 수 있다.
3.2.calloc(Contiguous Allocation)
C언어에서 동적 메모리를 할당할 때 사용되는 표준 라이브러리 함수이다. malloc과 유사하게 동적 메모리를 할당하지만 calloc은 메모리를 0으로 값을 초기화하여 할당한다.
- calloc 함수의 선언
calloc 함수는 C 표준 라이브러리의 stdlib.h 헤더 파일에 다음과 같이 선언되어 있다.
- calloc 함수의 구현
collac 함수는 할당할 개수, 할당할 자료형의 크기가 0이라면 NULL을 return하고, malloc함수를 사용해 void*를 return한 뒤, bzero와 같은 함수를 사용해 0으로 초기화한다.
- calloc 함수 사용 예시
malloc과 유사하게 arr은 메모리가 할당된 주소를 가리키는 변수고, calloc 또한 void*를 반환하므로 int*로 casting했다.
차이점은 calloc의 함수인자는 동적 할당할 개수와 하나의 데이터의 크기이다.
3.3. free 함수
free 함수는 C언어에서 동적으로 할당한 메모리를 해제하는 데 사용되는 표준 라이브러리 함수이다. 사용자가 더 이상 필요하지 않은 동적 메모리 블록을 반환하여 메모리 누수를 방지한다.
- free 함수의 사용법
해제할 메모리 블록의 포인터를 함수 인자로 넣으면 해제된다.
free 함수가 내부적으로 메모리 블록의 크기를 참조하여 정확한 해제를 수행하는 방식을 사용하기 때문에 포인터 하나만 사용하여도 그 블록의 모든 메모리를 해제할 수 있다.
3.4. 2차원 동적할당 방식
2차원 배열을 동적으로 할당한다면 포인터 포인터를 사용하는 방법이 있다. 각 행의 주소를 저장하는 포인터 배열을 생성하고 그 포인터 배열의 각 요소가 다시 각각의 열을 가리키도록 하는 방법이다.
- 2차원 동적할당 예시
- 동적 할당 하는 법
하나의 행은 열의 개수만큼의 요소를 가지는 배열이며, 그 배열들이 row만큼 모여 또 다시 배열을 이루는데 배열의 배열을 가리키는 변수를 arr로 선언한 것이다.
선언 방법은 row만큼 포인터 포인터로 선언하여 동적할당 한 뒤, col의 개수만큼 동적할당하는 것이다.
- 메모리 해제
각 행의 메모리를 먼저 해제한 뒤, 행 배열에 대한 메모리를 해제해야 한다.
이 때 순서가 바뀌면 안 된다. 행 배열에 대한 메모리를 먼저 해제하면 각 행의 메모리를 해제할 때 접근할 수 없기 때문이다.
- 그림 표현
'학부 수업 내용 정리 > 자료구조' 카테고리의 다른 글
Array (0) | 2025.03.12 |
---|---|
Recursion (0) | 2025.03.12 |
프로그램 실행 시 알아야 할 기본적인 메모리 구조 (0) | 2024.08.01 |
문자열 리터럴(string literal)에 대한 이해 (0) | 2024.08.01 |
변수와 리터럴의 차이 (0) | 2024.07.30 |