C - 동적 메모리 할당
메모리의 종류에는 크게 4가지로 분류된다.
1. 코드영역 : 실행할 프로그램의 코드가 저장되는 메모리 공간
2. 데이터 영역 : 전역 변수와 static변수가 할당되는 영역이며 프로그램 시작과 동시에 메모리에 할당되고, 프로그램 종료시까지 남아 있다.
3. 스택 영역 : 지역변수와 매개변수가 할당되는 영역, 함수를 벗어날 경우 소멸 한다.
4. 힙 영역 : 동적 할당된 메모리들이 존재하는 공간
메모리를 할당하는 2가지 방법에 대해 알아보자
1. 정적 메모리 할당 : 변수 선언을 통해 필요한 메모리를 확보하는 방법이다.
정확히 말하자면 컴파일 단계에서 메모리 공간을 할당받는 것이다.
int sum(int a, int b){
return a + b;
}
int main(void) {
int num1 = 3;
int num2 = 4;
static num3 = 5;
printf("%d", sum(num1, num2));
return 0;
}
위의 코드가 컴파일 될 때 변수들은
code | code | ||
Data | num3 = 5 | ====>>>>>> sum함수 종료 |
num3= 5 |
Stack | a = 3, b = 4, num1 = 3, num2= 4 |
num1 = 3, num2 = 4 | |
Heap | Heap |
데이터 영역은 "전역변수와 정적변수", 스택 영역은 "지역변수와 매개변수"가 저장이 된다는것을 알고 보면
정적변수로 선언된 num3는 데이터 영역에 저장이 되고 main함수에서 선언된 num1, num2와 sum함수의 매개변수인 a,b는 스택 영역에 저장이 된다.
정적할당의 장단점에 대해 알아보자
장점은 메모리 누수를 걱정하지 않아도 된다.
일단 컴파일을 한 후 메모리를 할당 받은 뒤엔 운영체제가 알아서 메모리 공간을 회수 해간다.
단점은 메모리 공간의 크기가 정해져 있어서, 더 큰 공간이 필요하더라도 추가해줄 수 없고, 더 작은 공간이 필요한 경우 메모리 공간의 낭비가 발생한다.
2. 동적 메모리 할당 : 실행 단계에서 메모리 공간을 할당 받는 것이다.
포인터를 사용해 직접 Heap영역을 가리켜 해당 공간을 빌리는 개념이다.
정리하자면 프로그램에서는 필요한만큼의 메모리를 시스템으로부터 할당을 받아서 사용하고, 사용이 끝나면 시스템에 메모리를 반납한다. 필요한 만큼만 할당을 받고 또 필요한 때에 사용하고 반납해 메모리를 효율적으로 사용할 수 있다. malloc()계열의 라이브러리 함수를 사용해서 할당 받을 수 있다.
쉽게 말하자면 수납 공간에서 물건을 꺼내는 것과 비슷하다. 동적 메모리의 사용이 끝나면 반드시 해당 메모리 영역을 명시적으로 반납을 해줘야 한다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int *pi;
pi = (int *)malloc(sizeof (int)); //malloc = 메모리를 할당해라
if(pi == NULL) {
printf("동적 메모리 할당에 실패했습니다.\n");
exit(1);
}
*pi = 100;
printf("%d\n", *pi);
//동적 메모리 사용한 이후에는 무조건 해당 메모리를 반환할 것
free(pi); //할당 해제
return 0;
}
출력 결과
100
동적 메모리 할당을 위해서는 반드시 #include <stdlib.h>를 넣어줘야 한다.
pi = (int *)malloc(sizeof (int)); 구문을 해석하면 int자료형(4)크기의 메모리를 할당해줘라 라는 뜻이다.
int *pi에 대해서 pi 는 어떤 일도 하지 않고 있는 ram의 특정 부분에 4크기에 해당하는 메모리를 int형으로 할당해준다. 그 후
int 포인터의 위치를 반환하는 것이다. 포인터를 이용해 더 어렵지만 메모리를 효율적으로 이용할 수 있다는 점.
만약 pi 의 값이 NULL(메모리 할당 실패)일시 그 사실을 알려주는 구문을 출력하고 조건에 충족 하지 않았을 경우
*pi에 100이란 값을 넣는다. 그후 free(pi)구문을 통해서 할당 받은 메모리를 다시 반납하는 구문이다.
동적 메모리로 100바이트를 할당 받아 알파벳을 출력하는 예제이다.
int main(void) {
char *pc = NULL;
int i = 0;
pc = (char *) malloc(100 * sizeof(char)); //총 100개의 문자를 받을 수 있는 공간을 할당 해달라는 구문
if(pc == NULL) {
printf("동적 메모리 할당에 실패했습니다.\n");
exit(1);
}
/*pc가 가리키는 포인터를 1씩 증가시키며 알파벳 소문자를 삽입한다.*/
for (int i = 0; i < 26; i++) {
*(pc + i) = 'a' + i; //*(pc+1)은 pc가 할당받은 주소 바로 옆에 할당받은 공간안의 값
}
/*아스키코드 0 = NULL을 의미*/
*(pc + i) = 0;
printf("%s\n", pc);
free(pc);
return 0;
}
int main(void) {
int *pi, i;
pi = (int *) malloc(5*sizeof(int));
if(pi == NULL){
printf("동적 메모리 할당에 실패했습니다. \n");
exit(1);
}
pi[0] = 100;
pi[1] = 200;
pi[2] = 300;
pi[3] = 400;
pi[4] = 500;
for (int i = 0; i < 5; i++) {
printf("%d\n",*(pi + i));
}
free(pi);
return 0;
}
출력 결과
100
200
300
400
500