Programming/C++

메모리 관리와 동적 할당

OKOK 2017. 7. 24. 22:32

프로그램을 실행시키기 위해서 메모리 공간이 필요하다. 지역 변수나 전역 변수를 선언하기 위해서도 메모리 공간이 필요하다. 그래서 운영체제는 본인이 실행시킨 프로그램의 실행을 위해서 메모리 공간을 할당해 준다. 이렇게 해서 할당되는 메모리 공간은 크게 스택, 힙 그리고 데이터 영역으로 나뉘어 진다. 할당 시기는 프로그램이 실행될 때마다 이며, 할당 장소는 메인 메모리이다. (여기서 말하는 메인 모메리는 RAM을 의미함) 할당 용도는 프로그램 실행 시 필요한 메모리 공간의 할당을 위함이다. 


데이터 영역은 전역 변수와 static 변수가 할당되는 영역이다. 이 영역에 할당되는 변수들은 일반적으로 프로그램의 시작과 동시에 할당되고, 프로그램이 종료되어야 메모리에서 소멸된다. 즉, 데이터 영역에 할당된 변수는 프로그램이 종료될 때까지 계속 존재한다는 특징을 지닌다. 전역 변수와 static 변수는 프로그램이 종료될 때까지 존재하는 변수들이다.


스택 영역은 함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역이다. 이 영역에 할당된 변수는 함수 호출이 완료되면 사라진다는 특징을 지닌다. 이는 다른 메모리 영역과 확실히 비교되는 특징이다. 예를 들어, stack 이라는 함수가 있다고 가정해 봅니다. 인자가 전달되면서 stack 이라는 함수가 호출되면, 일단 매개 변수가 a가 스택 영역에 올라가게 됩니다. 그리고 지역 변수 b가 스택 영역에 올라가게 됩니다. 반대로 stack 함수의 호출이 완료되고 나면, 변수 a, b는 스택 영역에서 사려져 버립니다.


힙은 프로그래머가 관리하는 메모리 영역입니다. 즉 프로그래머의 필요에 의해서 메모리 공간이 할당 및 소멸되는영역입니다. 


#include <stdio.h>


void fct1(int);

void fct2(int);


int a = 10;

int b = 20;


int main(void)

{

int m = 123;

fct1(m);

fct2(m);


return 0;

}


void fct1(int c)

{

int d = 30;

}


void fct2(int e)

{

int f = 40;

 

위 예제에서 보면 a, b라는 이름의 전역 변수가 선언되어 있다. 따라서 main 함수가 호출되기 전에 데이터영역에 a, b라는 이름의 변수가 각각 10과 20으로 초기화되어 올라간다. 또한,  데이터 영역에 할당되었으므로 당연히 프로그램이 종료될 떄까지 메모리상에 존재하게 된다. 


main 함수는 시스템에 의해서 자동적으로 호출된다는 점을 제외하면, 일반 함수와 차이가 없다. 변수 m도 main 함수 내에서 선언되었으므로 지역 변수다. 지역 분스는 함수가 호출되어 실행되는 동안에만 유효한 변수이므로, 지역 변수 m도 main 함수가 완료되기 전까지만 main 함수 내에서 유효할 것이다. 



배열 선언 시 반드시 상수만 써야 하는 이유


스택과 데이터 영역에 할당될 메모리의 크기는 컴파일되는 동안에 결정되어야 한다. 컴파일되는 동안이란 표현 대신 일반적으로 컴파일-타임이라는 표현을 많이 사용한다. 그래서 보통은 다음과 같이 표현한다. 데이터 영역과 스택에 할당될 메모리의 크기는 컴파일 타임에 결정되어야 한다. 예제에서 요구하는 바는 프로그램을 실행 시 사용자의 요구에 맞게 메모리(배열의 길이)를 할당해 주는 것이다. 즉, 런타임에 메모리의 크기를 결정하고 싶은 것이다. 이러한 용도로 사용하기 위해서 존재하는 메모리 공간이 바로 힙이다.  int * i = (int*) malloc(4); 첫 번째로 정수 4를 전달하면서 malloc 함수를 호출하고 있다. 따라서 힙 영역에 4바이트 메모리가 할당되고, 할당된 메모리의 주소가 void* 형으로 리턴된다. 두 번째로 리턴되는 void* 를 적절한 타입으로 형 변환한다. 세 번째로 미리 선언해 놓은 포인터 변수 i에다가 대입하고 있다. 


#include<stdio.h>

#include<stdlib.h>


int main(void)

{

int * a;

a = (int*)malloc(sizeof(int));

if (a == NULL)

{

puts("error");

exit(1);

}


*a = 20;

printf("value a : %d\n", *a);


free(a);

return 0;


int 형 변수를 저장할 수 있는 메모리 공간을 동적으로 할당하고 있다. 메모리 할당에 성공했는지 확인하고 있따. 메모리 부족과 같은 이유로 메모리 할당에 실패하는 경우 NULL포인터가 리턴된다고 언급하였다. 동적으로 할당된 메모리 공간에 정수 20을 저장하고 있다. 할당했던 메모리 공간을 해제하고 있따. 할당된 메모리 공간은 반드시 해제 되어야 한다. 


#include<stdio.h>

#include<stdlib.h>


void function(int);

int main(void)

{

int m = 0;

fputs("array length : ", stdout);

scanf_s("%d", &m);

function(m);


return 0;

}


void function(int i)

{

//int array[i];

int* array = (int*)malloc(sizeof(int)*i);

int j;

if (array == NULL) {

puts("error");

exit(1);

}


for (j = 0; j < i; j++)

array[j] = j + 1;

for (j = 0; j < i; j++)

printf("%d", array[j]);

printf("\n");


free(array);


malloc 함수 호출을 통해서 배열을 동적으로 힙 영역에 할당하고 있따. 따라서 프로그램이 실행되는 동안에 사용자가 입력하는 크기의 배열을 무리 없이 할당하게 된다. eixt 는 프로그램을 종료시키는 기능을 지니는 함수이다. 함수 호출시 전달되는 값 1은 프로그램이 어떠한 문제에 의해서 비정상적 종료를 한다는 것을 의미한다.