'동적 할당(Dynamic Allocation)' : 힙에 메모리를 할당하는 것
'정적 할당(Static Allocation)' : 스택과 데이터 영역에 메모리를 할당
'정적 할당(Static Allocation)' : 스택과 데이터 영역에 메모리를 할당
○ malloc 함수
malloc 함수는 동적으로 메모리를 할당하는 함수다. 곧 힙 영역에 메모리를 할당하는 함수라는 뜻이다.
다음은 함수의 원형이다.
#include <stdlib.h>
void* malloc(size_t size)
// 성공 시 할당된 메모리의 첫 번째 주소 리턴, 실패 시 ULL 포인터 리턴
void* malloc(size_t size)
// 성공 시 할당된 메모리의 첫 번째 주소 리턴, 실패 시 ULL 포인터 리턴
할당하고자 하는 메모리의 크기를 함수 호출 시 바이트 단위로 전달하면, 그 크기만큼 메모리를 힙에 할당하게 된다.
그리고 할당한 메모리의 주소(첫 번째 바이트의 주소)를리턴한다. 만약에메모리 부족으로 인해서 메모리 할당에 실패했다면,
NULL포인터가 리턴되므로, 리턴된 포인터가 NULL인지 아닌지를 확인해야 할 것이다.
<참고>"메모리의 첫 번째 주소를 리턴한다고? 그렇다면 힙에 할당한 배열이나 변수에 접근하려면 포인터를 사용하는수 밖에 없겠네!" 그렇다! 힙에 할당된 메모리 공간에 접근하려면 포인터를 사용해야 한다. 따라서 포인터가 익숙치 않거나 다소 기억이 흐릿하다면 이쯤에서 포인터에 대한 내용을 복습하는것도 좋을 것이다.
이제 한가지만 더 살펴보면 되겠다. 리턴형이 void*(void 포인터)인 이유이다.
malloc은 단순히 메모리만 할당하는 함수이다. 예를 들어서 4를 인자로 전달하면서 malloc 함수를 호출하는 경우 4바이트 메모리를 힙에 할당할 것이다. 그리고 난 다음에 malloc 함수는 다음과 같은 고민에 빠진다.
"4바이트를 힙 영역에 할당하기를 바라는 군. 좋아! 0x1000번지에서부터 4바이트를 할당하자. 이제 주소 값 0x1000을 리턴해야 하는데 어떤 타입으로 리턴하지? int형 데이터를 저장하려나? 그러면 int*형으로 리턴해야 겠네, 아냐! 4바이트니까 float형 데이터를 저장할 수도 있어. 혹시 문자열을 저장하려는 건 아닐까?"
그리고 다음과 같은 결론을 내린다. "그냥 void*형으로 리턴해야 겠다. 알아서 용도에 맞게 형 변환해서 쓰라고 하지 뭐"
다시 본론으로 돌아와서, malloc함수 호출시 전달하는 인자 정보만을 가지고는 리턴해야 할 주소 값의 포인터 타입을 결정짓지 못한다. 따라서 void* 타입으로 주소값을 리턴하는 것이다.
이제 리턴 타입이 void*인 이유를 알 수 있을 것이다. 그렇다면 여러분은 리턴된 포인터를 가지고 무슨 작업을 해야 하는가? 용도에 맞게 포인터를 형 변환해야 한다. 예를 들어 int형 데이터를 저장하기 위해서 메모리를 할당했다면, 리턴되는 void*를 int*로 변환해야 할 것이다.
int * i = (int*) malloc( sizeof(int) ); |
↓
int *i = (int*) malloc(4); |
● free 함수
힙(Heap) 영역에 메모리를할당하는 것과 더불어 할당된 메모리를 해제하는 것도 프로그래머가 신경써야 할 내용이다.
(컴퓨터가 알아서 해 주지 않는다.)
만약에 프로그램상에서 메모리를 동적으로(malloc함수를 이용해서)할당만 한다면 어떻게 될까?
적절한 시기에 할당해 놓은 메모리를 해제해 주지 않는다면, 결국에 가서는 메모리가 부족하게 될 것이다. 당장은 메모리 부족 현상이 발생하지 않는다 하더라도, 불필요한 메모리를 해제하지 않고 그냥 내버려 두는 것은 성능상의 이유로도 바람직하지 않다. 따라서 할당된 메모리가 더 이상 필요하지 않은 경우에는 반드시 해제시켜 줘야 한다. 다음은 동적으로 할당된 메모리를 해제시켜 주는 함수의 원형이다.
#include <stdlib.h>
void free(void* ptr)
void free(void* ptr)
해제하고자 하는 메모리 공간을 가리키는 포인터를 인자로 전달하면, 해당 포인터가 가리키는 메몸리 공간은 해제된다. 매게 변수의 타입으로 void*로 선언되어 있다. 따라서 어떠한 포인터도 인자로 전달될 수 있다.
다음 에제를 통해서 지금까지 언급해 온 malloc 함수와 free 함수의 사용 예를 확인해 보자.
malloc과 free함수의 문법적 이해를 돕기 위한 것이다.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int* a;
a = (int*) malloc(sizeof(int)); //메모리 할당
if(a == NULL) //메모리 할당의 성공 유무 확인
{
puts("메모리 할당에 실패!");
exit(1);
}
*a = 20;
printf("힙에 저장된 변수 a : %d \n", *a);
free(a); //메모리 해제
return 0;
}
#include <stdlib.h>
int main (void)
{
int* a;
a = (int*) malloc(sizeof(int)); //메모리 할당
if(a == NULL) //메모리 할당의 성공 유무 확인
{
puts("메모리 할당에 실패!");
exit(1);
}
*a = 20;
printf("힙에 저장된 변수 a : %d \n", *a);
free(a); //메모리 해제
return 0;
}
배열을 스택이 아닌 힙에 할당하게 된다면, array[j] 형식으로 선언 가능하다.
다음 예제를 살펴보자.
#include <stdio.h>
#include <stdlib.h>
void function(int);
int main (void)
{
int m =0;
fputs("배열의 크기를 입력하세요: ", stdout);
scanf( "%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("메모리 할당에 실패!");
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); //할당된 메모리 소멸
}
#include <stdlib.h>
void function(int);
int main (void)
{
int m =0;
fputs("배열의 크기를 입력하세요: ", stdout);
scanf( "%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("메모리 할당에 실패!");
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); //할당된 메모리 소멸
}
int* array = (int*)malloc(sizeof (int) *i); //동적 메모리 할당
/*
다음을 보면 malloc 함수의 전달 인자가 조금 복잡하게 되어 있다. malloc 함수는 전달되는 매개 변수의 크기만큼 바이트 단위를 할당해 주기 때문이다. 즉 5를 전달하면 5바이트를 할당해 주고, 10을 전달하면 10바이트를 할당해 준다. 그렇다면 크기가 5인 int형 배열을 할당하려면 어떻게 표현해야 하는가? int가 4바이트이므로 5X4 = 20, 따라서 malloc(20)하면 된다. 그러나 이러한 표현보다는 malloc(size0f(int)*5)가 훨씬 부드럽고 사용하기에도 편리하다. int가 2바이트 인지 4 바이트 인지 신경 쓸 필요가 없기 때문이다.
길이가 123인 double형 배열을 선언해 보라! double이 8바이트 였던가? 그렇다면 123X8은? 음 머리가 아프다. 그러나 다음 표현은 double이 8바이트 였는지 조차 몰라도 사용 가능하다. malloc(szeof(double) * 123).
*/
2차 배열에서 malloc 사용
function(int i)
{
int j
int** array = (int**)malloc(sizeof (int) *i);
for(j = 0; j < i ; j++)
{
array[j] = (int*) malloc(sizeof(int) * i);
}
free(array);
//(int*) int형 포인터 캐스터 연산자, 형변환
//malloc은 주소를 반환하는 함수
//초기화는 for문 memset();
출처 : http://blog.naver.com/37441/80108113848
function(int i)
{
int j
int** array = (int**)malloc(sizeof (int) *i);
for(j = 0; j < i ; j++)
{
array[j] = (int*) malloc(sizeof(int) * i);
}
free(array);
//(int*) int형 포인터 캐스터 연산자, 형변환
//malloc은 주소를 반환하는 함수
//초기화는 for문 memset();
출처 : http://blog.naver.com/37441/80108113848
◐ calloc 함수
calloc 함수는 malloc 함수와 같은 기능을 가지고 있다. 즉 메모리를 동적으로 힙(heap)영역에 할당할 때 사용한다. 다만 사용하는 형태가 조금 다를 뿐이다.
#include <stdlib.h>
void *calloc(size_t elt_count, size_t elt_size)
//성공 시 할당받은 메모리의 포인터(void* 형), 실패 시 NULL 리턴
void *calloc(size_t elt_count, size_t elt_size)
//성공 시 할당받은 메모리의 포인터(void* 형), 실패 시 NULL 리턴
위 함수는 호출시 "elt_size 크기의 변수를elt_count개 만큼 저장할 수 있는 메모리 공간을 힙 영역에 할ㄹ당하라"라는 의미를 지닌다. 따라서 malloc(elt_count * elt_size) 함수 호출과동일한 효과를 나타낸다.
int* arr = (int*)calloc(size, sizeof(int)); | == | int* arr = (int*)malloc(size*sizeof(int)); |
다음에 소개되는 예제는 사용자가 요구하는 만큼의 메모리 공간을 동적으로 할당하고 그 크기만큼 숫자를 입력받는 예제이다.
#include < stdio.h >
#include < stdlib.h >
int main()
{
int size, i;
int * arr;
printf( "Enter the number, to memory alloc : ");
scanf("%d", &size);
arr = (int*) calloc(size, sizeof(int) );
//arr = (int*)malloc(size*sizeof(int));
for(i = 0; i < size; i++)
scanf("%d", &arr[i]);
for(i = 0; i<size; i++)
print("%d번째 요소 : %d \n", i, arr[i]);
free(arr);
return 0;
}
#include < stdlib.h >
int main()
{
int size, i;
int * arr;
printf( "Enter the number, to memory alloc : ");
scanf("%d", &size);
arr = (int*) calloc(size, sizeof(int) );
//arr = (int*)malloc(size*sizeof(int));
for(i = 0; i < size; i++)
scanf("%d", &arr[i]);
for(i = 0; i<size; i++)
print("%d번째 요소 : %d \n", i, arr[i]);
free(arr);
return 0;
}
출처 : C프로그래밍 _ 윤성우저
'Language > C언어' 카테고리의 다른 글
배열을 함수 인자로 전달받는 방법 (0) | 2011.02.26 |
---|---|
문자열 배열 (0) | 2011.02.26 |
C 언어의 메모리 구조 (0) | 2010.09.27 |
[Random 함수] 난수 발생. (0) | 2010.09.26 |
[포인터] 함수 포인터 배열 (0) | 2010.09.03 |