본문 바로가기
C

동적할당

by stdlib.h 2016. 4. 3.

할당의 필요성


프로그램이 실행되기위해서는, 메모리가 필요한다.

왜냐하면, 실행파일 자체가 메모리에 로드되어야 실행될 수 있고,

프로그램이 작업을 위해 선언하는 변수도 메모리에 할당되기 때문이다.


만약 int total, average 같은 변수를 선언한다고 하면,

컴파일러는 이 두변수들이 값을 제데로 보관할 수 있도록 타입에 맞는 크기만큼

메모리를 할당한다.

정수형이나 실수형은 아주작아서 이런 변수들때문에 문제가 생길경우는 드물다.


동적 할당(Dynamic Allocation) 이란 프로그램을 작성할때

메모리 필요량을 컴파일러가 지정하는 정적 할당과는 달리 실행중에 필요한 만큼 메모리를 할당하는 

기법이다.

만약 학생들의 점수를 저장하는 변수를 만들때, 보통은 배열을 사용할 것이다.


만약 학생수가 50명이라면

int score[50] 이면 된다.

이렇게 선언하면 50명분의 메모리 공간이 확보된다.

뭐 학생수가 1000이면 100개를 이런식으로 얼마든지 더 크게 늘리 수 있다.

모자란 것은 문제가 되지만 조금 남는것은 문제가 되지 않으므로 여유분까지

고려하여 필요한만큼 메모리를 정적할당하면 된다.


그러나 이 최대량을 예측할수 없는 경우가 있다.


특정학교가 아닌,  임의의 학교를 위한 프로그램이라면, 어느학교는 50명이고, 어떤학교는 10명일 수도 있다. 그럴때 배열을 100만정도로 충분하게 정적할당하는 것은 메모리를 지나치게 낭비하게 되므로 좋지 않다.

그렇다고해서 다음과 같은 코드가 가능하진않다.


int n;

printf("학생수를 입력해주십시오\n");

scanf("%d", &n);

int score[n];


언뜻보기에는 가능할것 같으나, 에러가 발생한다.

왜냐하면, 배열의 선언문의 크기값은 상수만 가능하기 때문이다.


왜냐하면, n 이라는 변수값은 실행중에 입력하는 값이기 때문에, 컴파일 할 때는

이 값이 얼마가 될지 알 수 없다. 때문에, 필요량을 작성중에 결정할 수없을때는 동적할당을 사용해야 한다.



또 다른 경우는 임시적인 메모리가 필요할 때이다.

텍스트파일에서 어떤 문자열을 찾을때 의 버퍼를 예시로 들 수 있다.

파일크기만큼 동적할당한 후 원하는 작업만 하고 해제하면 되기 때문이다.




동적할당된 메모리는 이름이 없는 변수라고 할 수 있다.

독점적인 메모리 영역을 차지하고 있으므로 일단 값을 기억할 수 있지만 이름이 없으므로, 오로지 포인터로만 접근이 가능하다.

그래서 malloc 함수나 calloc 함수등이 리턴하는 포인터는 적절한 타입의 포인터 변수수로 대입받아야 한다.

시작번지를 잃어버리면 메모리를 쓸수도없고 해제도 안된다.




할당 및 해제


메모리를 동적으로 할당 및 해제할 때는 다음 두 함수를 사용한다.


void* malloc(size_t size);

void free(void *memblock);



malloc 함수에 대하여 알아보자면,


인수로 필요한메모리양을 바이트 단위로 전달하면, 요쳥한 만큼 할당된다.

size_t 는 메모리의 양을 나타내는 단위인데 _t 로 끝나는 사용자 정의 타입은 표준에 의해 반드시 정의하도록 되어 있으므로 기본타입과 거의 대등한 자격을 가진다. 카더라


10바이트가 필요하면 malloc(10)이라 호출하고 1000바이트가 필요하면 malloc(1000) 라고 호출하면 된다. 실행중에 할당하는 것이므로, malloc(n) 과 같이 변수도 사용할 수 있다.

malloc은 응용프로그램이 필요로하는 양만큼 할당을 요청하여 힙영역을 찾아 요쳥한 만큼 할당하여 시작번지를 리턴한다.(카더라)


인트형인지 어떤형인지 모르기때문에 void* 로 리턴한다.

때문에 원하는 타입으로 캐스팅을 해주어야 한다.


free 함수는 동적으로 할당된 메모리를 해제한다.

응용 프로그램은 메모리를 다 사용한 후에 반드시 free함수를 호출하여 해제해야한다.




다음은 할당하는 예시이다.


int *ar;

ar = (int*)malloc(sizeof(int)*10);

free(ar);



앞서 기재했지만, 사용하기 위해서는 시작번지를 기억해야 하므로 포인터 변수가 필요하다.


(위의 경우는 정수형 변수를 위한 메모리를 할당하는 것이므로 정수형 포인터ar이다.)


위의 코드는 40바이트를 할당했는데, int 가 반드시 4바이트란 보장이 없으므로 sizeof 연산자를 사용해야 한다.



이후 ar이 가리키는 번지는 마치 ar[10]라고 선언한 배열의 ar과 같아지며,

메모리 내에서의 실제 모양과 용도, 적용되는 문법도 배열과 같다.





malloc 함수가 할당에 실패하면 에러의 표시로 NULL 을 리턴한다.

그래서 이함수를 호출할때는 malloc 이 리턴한 변지를 점검하는게 좋다.


사실 free를 호출하지 않아도 프로그램이 종료되면 메모리를 알아서

회수한다. 하지만 해제하지 않아도 좋다는것은 아니다.






재할당.



calloc 함수는 malloc 함수와 마찬가지로 메모리를 할당하되, 필요한 메모리양을 지정하는 방법만 다르다.


void* calloc(size_t num, size_t size);


첫 번째 인수 num은 할당할 요소의 개수이고, size는 요소의 크기이다.


malloc은 필요한 메모리 바이트 단위 하나로만 전달받지만,

calloc 은 두 개의 값으로 나누어 받는다는 점이 다르다.


차이를 비유하자면,


malloc 은 10바이트짜리 주세여 이고,

calloc 은 10바이트짜리 몇개 주세여 이다.



그래서 다음 두 문장은 같다.


ar=(int*)malloc(10);

ar=(int*)calloc(1, 10);


또 다른 차이점은,

malloc으느 할당만 하므로 쓰레기값이 있지만,

calloc 은 0으로 모두 초기화된다.

물론 malloc 후 memset 도 가능하지만 calloc이 편하다.




다음은 재할당을 하는 realloc 이다.


원형은 다음과 같다.

void* realloc(void* memblock, size_t size);


첫 인수로 malloc 이나 calloc 으로 할당된 메모리의 시작 번지를 주고, 두 번째 인수로

재할당할 크기를 전달한다.

만약 첫 인수가 NULL 이면 새로 메모리를 할당하므로 malloc 과 같아진다.

size 가0이라면 할당을 취소하는것이므로, free와 같다.

재할당 후에는 새로운 메모리의 번지를 리턴하는데 원래값과 같을수도있고 다를수도 있다.

확대도 가능하고 축소도 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
    char *ptr = NULL;
    char ch;
    int i = 0;
    while ((ch = getchar()) != '\n')
    {
        ptr = (char*)realloc(ptr, sizeof(char*)*(i + 1));
        *(ptr + i) = ch;
        i++;
    }
    *(ptr + i) = '\0';
    puts(ptr);
    free(ptr);
}
 
cs


'C' 카테고리의 다른 글

strcmp 구현  (0) 2016.04.04
배열과 포인터  (0) 2016.04.03
포인터  (0) 2016.03.31
C언어]재귀 - 피보나치 수열  (0) 2016.03.29
C언어] 1부터 N까지의 합  (0) 2016.03.29