Jiyong's STUDY

메모리의 동적 할당. malloc과 free 본문

프로그래밍/C

메모리의 동적 할당. malloc과 free

Kingjiyong 2018. 5. 31. 04:56

메모리 공간을 할당하고 소멸시키는 malloc과 free 함수


#include <stdlib.h>

void *malloc(size_t size);


malloc 함수는 힙 영역에 메모리 공간을 할당한다.

반환형이 void형 포인터임을 생각하여 용도에 따라 반환값에 대한 형변환을 시켜주어야 한다.

인자로 size를 받는데, 이는 메모리 공간의 크기를 뜻한다.

예를 들어 int형 변수 하나를 할당하기 위하여 malloc 함수를 선언하였다면 sizeof(int) 처럼 명시해주어야 한다!


참고로 메모리 할당에 실패하였다면 널 값을 반환한다. 즉 할당을 받고자 선언한 포인터는 널 포인터가 된다.


#include <stdlib.h>

void free(void *ptr);


malloc 함수를 통하여 할당한 메모리 공간은 free 함수를 통하여 소멸이 가능하다.

사실 free 함수를 굳이 사용하지 않아도 프로그램이 종료되면 힙 영역의 메모리는 소멸된다.

그렇다면 왜 free 함수를 꼭 굳이 사용해야 하는가?


이는 이전에 배웠던 fopen과 fclose의 관계와 비슷하다.

불필요한 리소스의 소멸을 위하여 사용된다. 

힙 영역이 가득 차 문제가 생기는 것을 방지하기 위하기도 한다. 



메모리의 동적 할당이란 무엇인가?


스택 영역과 데이터 영역에 할당되는 메모리의 공간은 정적이다.

스택 영역의 경우에는 함수가 호출되면 할당되며, 반환이 되면 소멸된다.

데이터 영역의 경우에는 프로그램이 실행되면 할당되며, 종료되면 소멸된다.

이를 메모리의 정적 할당이라고 한다.


하지만 힙 영역의 경우에는 사용자가 직접 할당하고 소멸한다. (위에서 본 함수들을 통하여)

계속하여 할당되고, 소멸되어 이는 동적이라고 볼 수 있다.

이를 메모리의 동적 할당이라고 한다.


여기서 궁금증이 생길 수 있다.

굳이 동적 할당을 하여야 하는가?

지역 변수, 전역 변수, static 지역 변수를 통하여 우리는 문제를 해결해왔다.

하지만 이 세 개의 변수들을 통해서 불가능한 문제는 많다.

이런 경우에 사용자는 동적 할당을 하여 해결하게 된다.

그러한 문제의 예시를 보면


#include <stdio.h>


char* Example(void) {

char str[20];

printf("input string : ");

scanf("%s", str);

return str;

}


int main() {

char *ptr1=NULL;

char *ptr2=NULL;

ptr1=Example();

puts(ptr1);

ptr2=Example();

puts(ptr2);


puts(ptr1);

puts(ptr2);

}


결과>> 

input string : 처음에 입력할 문자열

처음에 입력한 문자열

input string : 다음에 입력할 문자열

다음에 입력한 문자열

다음에 입력한 문자열

다음에 입력한 문자열


이전 글에 있던 예제와 유사하다.

설명했듯이, Example의 지역변수 str을 반환받아 main 함수의 포인터에 저장하는 방식이다.

첫 경우에는 문제가 없이 입력했던 문자열의 출력이 잘 된다.


하지만 마지막에 두 번 호출한 puts 함수의 결과는 어떤가?

ptr2이 가리키던 배열을 ptr1도 가리키고 있다.

즉 두 함수의 결과는 같다.


이것이 지역 변수의 특징이다. 함수가 반환 되면 할당된 메모리 공간은 소멸된다.

이전에도 말했듯이 소멸은 즉 초기화가 아니라 사용하지 않는 공간의 상태로 바꾸는 것이다.


그렇다면 이번엔 전역 변수를 사용하여 해결을 해보자


#include <stdio.h>


char str[20];


char* Example(void) {

printf("input string : ");

scanf("%s", str);

return str;

}


int main() {

char *ptr1=NULL;

char *ptr2=NULL;

ptr1=Example();

puts(ptr1);

ptr2=Example();

puts(ptr2);


puts(ptr1);

puts(ptr2);

}


결과는 마찬가지. static 지역 변수도 다를 바가 없다.


Example 함수를 접근하는 수 만큼 지역 변수나 전역 변수를 미리 할당해 놓는다면?

그러한 경우에는 매개 변수로 전달을 하는 수 밖에 없다.


그러므로 이 문제를 해결하기 위해서는 Example 함수에 접근 할 때 마다 메모리 공간을 따로 할당하는 수 밖에 없다.


이제 이 문제를 해결해줄 동적 할당을 해 보자


#include <stdio.h>

#include <stdlib.h>


char* Example(void) {

char *str=(char *)malloc(sizeof(char)*20);

printf("input string : ");

scanf("%s", str);

return str;

}


int main() {

char *ptr1=NULL;

char *ptr2=NULL;

ptr1=Example();

puts(ptr1);

ptr2=Example();

puts(ptr2);


puts(ptr1);

puts(ptr2);

free(ptr1);

free(ptr2);

}


드디어 제대로 된 결과가 나온다!

malloc 함수를 통하여 Example 함수를 호출할 때 마다 각각의 메모리 공간을 할당해주었기 때문에

각기 다른 공간을, 즉 다른 주소값을 반환을 받게 되었다.


마지막으로 동적 할당을 통하여 할당된 힙 영역은

포인터를 사용해야먄 접근이 가능하다.