본문 바로가기

Data Structure [C]/문돌이도 할 수 있는 [C언어 자료구조]

#17 [C 자료구조] 동적/정적 메모리 할당할당

자료구조를 배우다가 동적 메모리, 정적 메모리, 동적 프로그래밍, 정적 프로그래밍 등등의 동/정적 단어를 많이 접할 수 있다. 영어로 풀어 쓰면 좀 더 이해하기 쉽다. 진짜

 

  • 정적 메모리 할당 (Static Memory Allocation)
  • 동적 메모리 할당 (Dynamic Memory Allocation)

정적은 정해진 크기, 동적은 알고리즘에 따라서 다른 메모리를 할당하는 것이다ㅎㅎ

조금 더 세부적으로 배워보자.

 

정적 메모리 할당

- 프로그램 시작 전에 미리 정해진 크기의 메모리를 할당하는 것

- 처음에 결정된 크기보다 더 큰 입력이 들어오면 처리 못함

- 더 작은 입력이 들어온다면 남은 메모리 낭비

 

딱봐도 쉽지만 비효율적이라는 것이 느껴지지 않는가?

우리가 처리했던 대부분의 메모리는 이렇게 할당 되었다. 우리가 하는 일이 늘 그렇지 뭐...흑흑

int i, j;
int buffer [100];
char name[] = "data structure";

buffer가 심히 낭비되고 있는 모습

 

동적 메모리 할당

- 프로그램 실행 도중에 동적으로 메모리를 할당

- 컴파일 할 때 미리 안정해짐

- 사용이 끝나면 시스템에 메모리 반납

- 매우매우 효율적

- 소스코드가 복잡함(내가 고생함)

- 메모리를 다 사용한 다음에 반드시 해제시켜줘야함. 안한다면 메모리 누수 효과 발생

 

#include <stdlib.h> //동적 메모리 관련 함수 불러오기

...
int *ptr = NULL;
int size = 100;

ptr = (int*) malloc (sizeof(int)*size); // malloc() 메모리 할당
...

free ( ptr ); // 메모리 해제

ptr주소 값이 int의 사이즈에 의해 메모리 크기가 결정됨을 볼 수 있다.

 

malloc() 함수

stdlib.h 헤더 안에 있는 함수다.

malloc함수는 바이트 단위로 메모리를 할당한다.

메모리 블럭의 첫 번째 바이트에 대한 주소를 반환하는데, 요청 값이 없으면 NULL을 반환한다.

 

int형 데이터 저장을 위한 메모리 공간을 위해서는

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

이런식으로 p의 크기를 결정해주면되고

 

char형 데이터 저장을 위한 메모리 공간을 위해선

char *p;
p = (char*) malloc( sizeof(char));

이런식으로 주소의 메모리를 설정해준다.

 

다시 말하지면 malloc은 다음과 같은 형식을 띈다.

void *malloc(size_t size);

 

free() 함수

void free(void *ptr);

위와 같은 형태로 ptr에 할당되었던 메모리 블록을 시스템에 반납한다.

반납할때는 value를 써줘야하기 때문에 *를 붙인다.

 

실제로는 다음과 같이 사용된다!

int *p;
p = (int*) malloc(sizeof(int));
free(p);

 

포인터를 이용한 메모리 할당

이렇듯 동적 메모리 할당은 '포인터'로 이루어진다.

포인터가 값이 할당된 주소를 가리키니 포인터를 활용하는 것은 당연지사!!

동적 메모리가 사용되고 다시 반납되는 과정을 보도록 하자.

 

#include <stdio.h>
#include <stdlib.h>

int main(void) {
int *pi = NULL; char *pc = NULL;

    pi = (int *) malloc ( sizeof(int) ); // 동적 메모리 할당
    if ( pi == NULL ) { printf("동적 메모리 할당 오류\n"); exit(1); }
      *pi = 100; // 동적 메모리 사용
      printf("%d\n", *pi);
    free(pi); // 동적 메모리 반납
    
    pc = (char *) malloc ( sizeof(char) ); // 동적 메모리 할당
    if ( pc == NULL ) { printf("동적 메모리 할당 오류\n" ); exit(1); }
      *pc = 'm'; // 동적 메모리 사용
      printf("%c\n", *pc);
    free(pc); // 동적 메모리 반납
    
  return 0;
} 

실제 값을 지정하지 않고 *pi, *pc만을 가정한다. malloc함수로 동적 메모리를 할당하고 실제로 사용한다.

그리고 마지막으로 free함수로 동적 메모리를 반납한다!!

 

포인터로 배열을 지목하는 방법도 어렵지 않다.

#include <stdio.h>
#include <malloc.h>
int main(void) {
    int i, size=5;
    int *arr;
    
    arr = (int*) malloc ( sizeof(int) * size );
    
    for ( i=0; i<size; i++ ) {
        arr[i] = i;
    }
    for ( i=0; i<size; i++ ) {
    	printf("%d\n", *(arr+i));
    }
    free (arr);
    return 0;
}

여기선 arr또한 int로 받아 동적 메모리를 할당하고 arr안에 int형 숫자 i를 차례대로 넣어준다.

그리고 다시 i를 출력하는데 이 때 포인터로 값을 참조했다. 이후 arr의 메모리들을 해방!! 시켜준다.

 

그 외의 동적 메모리 함수들

calloc()

void *calloc(size_t n, size_t size);

0으로 초기화된 메모리를 할당하는 함수다.

malloc은 어떠한 값의 메모리가 들어갈지 지정해줘야하지만 calloc은 무조건 int형 0만 쏙쏙 집어 넣는다.

realloc()

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

할당하였던 메모리 블록의 크기를 변경하는 것이다. malloc에서 지정해줬던 사이즈를 다시 키우거나 줄이는 작업이 필요할 때 쓴다.

int *p;
p = (int*) malloc (5 * sizeof(int));
p = (int*) realloc (p, 7 * sizeof(int));