모노산달로스의 행보
[C programming] 동적 메모리 할당 본문
C programming - 동적 메모리 할당
리눅스 환경에서 네트워크 프로그래밍을 공부하기 위해서 C언어를 다시 복습해야 할 필요성을 느꼈습니다. 따라서 이번 기회에 배열부터 전처리기까지 내용들을 정리하겠습니다.
동적 메모리란?
프로세스의 메모리 구조는 위와 같이 4개로 구분됩니다. 그중에서 힙 영역은 프로그램이 실행되는 동안 동적으로 메모리를 할당할 수 있는 영역을 의미합니다. 힙 영역의 특징으로서 프로그래머가 요구할 경우 런타임 중에 동적 메모리 할당이 이루어집니다. 그렇다면 왜 동적 메모리 할당을 요청할까요?
int array[5];
array[0] = 10, array[1] = 20, array[2] = 30;
int array[2];
array[0] = 10, array[1] = 20, array[2] = 30;
정적으로 메모리를 할당하는 경우 프로그래머가 필요한 메모리 크기를 예측할 수 없는 경우가 발생합니다. 위와 같이 배열의 크기를 다 사용하지 못해 낭비되거나 크기 이상을 사용하여 에러가 발생하는 경우가 그 예시입니다.
#include <stdlib.h>
void* malloc (size_t size)
#include <stdlib.h>
void free (void* p)
malloc() 함수와 free() 함수를 통해서 메모리를 할당하고 해제할 수 있습니다.
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int* p = NULL;
p = (int*)malloc(sizeof(int));
if(p == NULL)
printf("힙 영역에 동적 메모리 할당 실패\n");
*p = 10;
printf("주소 : %x \n", p);
printf(" 값 : %d \n",*p);
free(p);
p = NULL;
return 0;
}
포인터 변수 p를 선언하고 (int*) malloc(sizeof(int))와 같이 초기화를 하였습니다. 이제 포인터 p는 힙 영역에 할당된 4바이트의 공간을 가리키게 됩니다. 이후 값을 10으로 초기화하는 과정도 문제없이 이어집니다. 동적 메모리 사용이 끝나면 free(p)를 통해서 메모리를 해제해 줍니다.
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int i = 0;
int* p = (int*)calloc(4, sizeof(int));
if(p == NULL)
printf("힙 영역에 동적 메모리 할당 실패\n");
for(i=0; i<4; i++) {
p[i] = i;
printf("주소: %x \n", &p[i]);
printf("값: %d \n", p[i]);
}
free(p);
p = NULL;
return 0;
}
이번에는 malloc() 함수가 아닌 calloc() 함수를 사용했습니다. 해당 함수는 두 개의 인자를 받아서 동적 메모리를 할당합니다. 첫 번째 인수는 메모리의 크기이며 두 번째 인수는 메모리의 데이터 타입을 의미합니다.
malloc() 함수와 가장 큰 차이점은 값을 0으로 초기화한다는 것입니다. malloc() 함수의 경우 값을 초기화하지 않으면 0이 아닌 쓰레기 값이 출력되게 됩니다.
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int i=0;
int* p=(int*) malloc(sizeof(int)*2);
p[0] = 10;
p[1] = 20;
p = (int*) realloc(p, sizeof(int)*4);
p[2] = 30;
p[3] = 40;
for(i=0; i<4; i++)
printf("p[%d] : %d \n", i, p[i]);
free(p);
p = NULL;
return 0;
}
위에서 보았던 malloc()과 calloc() 함수는 메모리가 할당되면 변경할 수 없습니다. 이러한 점을 보완하기 위해서는 realloc() 함수를 사용할 수 있습니다. 위 예제와 같이 malloc() 함수를 통해 int 자료형을 저장할 2의 크기의 동적 메모리를 할당했습니다. 이후 realloc을 통해서 포인터 p가 가리키는 힙 영역의 크기를 4로 지정합니다. 그렇게 되면 p[2]와 p[3]에 값을 초기화하여도 문제가 없습니다. 즉, 동적으로 할당된 메모리의 크기가 변경된 것입니다.
동적 메모리 사용 시 유의점
동적 메모리를 사용할 때는 메모리 누수와 Dangling 포인터 문제를 유의해야 합니다.
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int* a = (int*) malloc(sizeof(int) * 3);
int* b = (int*) malloc(sizeof(int) * 2);
b = a;
free(a);
free(b);
return 0;
}
위와 같은 예제에서 문제 점은 무엇일까요? a와 b 포인터가 동적 메모리를 할당받았습니다. 그런데 b 포인터가 a 포인터의 메모리 주소를 가리키게 되었습니다. 이후 free를 통해서 메모리를 해제해 주어도 원래 b 포인터가 할당받은 메모리는 해제되지 않습니다.
이를 메모리 누수(Memory Leak)이라고 합니다.
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int* a = (int*) malloc(sizeof(int));
*a = 10;
free(a);
*a = 20;
return 0;
}
위와 같은 경우는 어떤가요? a 포인터가 동적 메모리를 할당받아 10이라는 값을 초기화했습니다. 그리고 동적 메모리를 해제하였는데 포인터 a는 여전히 사라진 메모리를 가리키고 있습니다. 이후 사라진 메모리에 값 20을 할당하는 것은 문제가 발생할 수 있습니다. 이를 Dangling Pointer 즉, 사라진 메모리에 매달려있는 포인터라고 합니다.
'ProgrammingLanguage > C' 카테고리의 다른 글
[C programming] 스택(Stack) (1) | 2024.04.19 |
---|---|
[C programming] 연결 리스트 (Linked List) (0) | 2024.04.18 |
[C programming] 구조체와 열거형 (0) | 2024.04.17 |
[C programming] 표준 함수 (0) | 2024.04.16 |
[C programming] 문자열을 가리키는 포인터, 포인터 변수 상수화 (0) | 2024.04.10 |