1.동적 메모리 할당이란?
- 프로세스는 더 큰 메모리를 할당해서 사용할 수 있도록 힙(Heap)영역을 제공한다.
- 힙영역은 지역변수와 매개변수등을 저장하는 스택(Stack)영역과 달리 실행시점에 원하는 크기만큼 메모리를 할당할 수 있습니다.
- 메모리 사용이 끝나면 언제든지 할당한 메모리 공간을 해제할 수 있습니다.
1.1 malloc
- 힙은 스택처럼 관리되는 공간이 아니라서 변수를 선언하는 행위로 메모리를 할당할 수 없습니다. 그렇기 때문에 C 표준 함수인 malloc과
free를 통해서 메모리 할당 및 해제 해야합니다.
- 함수 원형
void *malloc(size_t size); /* size_t는 unsigned int와 같음 */
- void*를 사용하면 형 변환을 해야하는 불편함이 있기 때문에 주소를 받는 시점에 사용할 포인터에 미리 형 변환을 사용하는 것이 좋다.
- 예시 코드(int로 형 변환해서 받음)
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr_1[5]; // 배열 선언
int *arr_2; // 포인터 변수 선언
int i;
for(i = 0; i < 5; i++) {
arr_1[i] = i+1; // 배열에 값 대입
}
arr_2 = (int*) malloc(sizeof(int)*5); // 메모리 할당, 배열의 크기만큼 할당하기 위해 5를 곱함
for(i = 0; i < 5; i++) {
arr_2[i] = arr_1[i];
printf("%d ", arr_2[i]);
}
return 0;
}
1.2 free
- free 함수는 힙 영역에 할당된 메모리를 해제하는 함수입니다.
- free 함수를 사용하지 않으면 메모리를 낭비하게 되고 언젠가는 메모리가 부족한 현상이 발생할 것 입니다.
- 함수 원형
void free(void* ptr);
- 예시 코드
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr_1[5]; // 배열 선언
int *arr_2; // 포인터 변수 선언
int i;
for(i = 0; i < 5; i++) {
arr_1[i] = i+1; // 배열에 값 대입
}
arr_2 = (int*) malloc(sizeof(int)*5); // 메모리 할당, 배열의 크기만큼 할당하기 위해 5를 곱함
for(i = 0; i < 5; i++) {
arr_2[i] = arr_1[i];
printf("%d ", arr_2[i]);
}
free(arr_2); // free함수를 이용하여 메모리 해제
return 0;
}
1.3 calloc
- calloc은 malloc과 힙 영역에 할당하는 것은 똑같습니다. 하지만 calloc은 할당된 메모리를 전부 0으로 초기화 시켜줍니다.
- 함수 원형
void *calloc(size_t n, size_t size);
- 위의 코드는 size 크기의 변수를 n 개 만큼 저장할 수 있는 메모리 공간을 할당하라는 의미를 갖습니다.
- 예시 코드
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr_1[5]; // 배열 선언
int *arr_2; // 포인터 변수 선언
int i;
for(i = 0; i < 5; i++) {
arr_1[i] = i+1; // 배열에 값 대입
}
//arr_2 = (int*) malloc(sizeof(int)*5); // 메모리 할당, 배열의 크기만큼 할당하기 위해 5를 곱함
arr_2 = (int*) calloc(5, sizeof(int)); // sizoe(int)크기의 변수를 5개 저장할 수 있는 공간할당
for(i = 0; i < 5; i++) {
arr_2[i] = arr_1[i];
printf("%d ", arr_2[i]);
}
free(arr_2); // free함수를 이용하여 메모리 해제
return 0;
}
1.4 realloc
- 이미 할당된 공간의 크기를 줄이거나 늘릴 때 realloc 함수를 사용합니다.
- 함수 원형
void* realloc(void* memblock, size_t size);
- 이미 할당한 포인터 변수를 memblock에 넣고, 바꾸고 싶은 공간의 크기를 size에 입력해서 사용합니다.
- 예시 코드
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr_1[10]; // 배열 선언
int *arr_2; // 포인터 변수 선언
int i;
for(i = 0; i < 10; i++) {
arr_1[i] = i+1; // 배열에 값 대입
}
arr_2 = (int*) malloc(sizeof(int)*5); // 메모리 할당, 배열의 크기만큼 할당하기 위해 5를 곱함
for(i = 0; i < 5; i++) {
arr_2[i] = arr_1[i];
printf("%d ", arr_2[i]);
}
printf("\n");
// sizeof(int) = 4바이트
realloc(arr_2, sizeof(int)*10); // arr_2의 메모리를 40바이트로 재 할당
// arr_2의 메모리 크기 : 20바이트 -> 40바이트
for(i = 0; i < 10; i++) {
arr_2[i] = arr_1[i];
printf("%d ", arr_2[i]);
}
free(arr_2); // free함수를 이용하여 메모리 해제
return 0;
}
2. 동적 메모리 할당의 장단점
장점
- 힙에 동적으로 사용하는 메모리는 스택에 비해 큰 크기의 메모리를 할당할 수 있으며, 할당하고 해제하는 시점도 프로그래머가 직접 정할 수 있다.
- 동적 메모리 할당은 실행 중에 필요한 메모리를 할당하므로, 메모리 요구 사항이 실행 시간에 동적으로 변경될 수 있습니다. 이는 프로그램이 더 효율적으로 메모리를 사용하고, 유연하게 대처할 수 있도록 해줍니다.
- 정적 메모리 할당 방식에서는 프로그램이 필요로 하는 최대 메모리 양을 미리 예상하여 할당해야 합니다. 하지만 동적 메모리 할당은 필요한 만큼의 메모리만 할당하므로, 메모리 사용량을 최적화하여 효율적인 메모리 관리가 가능합니다.
단점
- 동적 메모리 할당을 사용할 때, 메모리를 할당한 후에는 반드시 해당 메모리를 해제해야 합니다. 그렇지 않으면 메모리 누수가 발생하여 할당된 메모리를 더 이상 사용할 수 없게 됩니다.
- 동적 메모리 할당을 반복적으로 수행하면, 메모리가 작은 조각들로 나뉘어지는 메모리 단편화가 발생할 수 있습니다.
'C언어' 카테고리의 다른 글
[C] malloc-lab 구현 (Implicit, Explicit, Segregated) (0) | 2023.05.18 |
---|---|
[C] Linux/gcc 사용법 , vi 에디터 명령어 (0) | 2023.05.05 |