jam 블로그

[C] 25. 메모리 관리와 동적 할당 본문

개발 및 관련 자료/C

[C] 25. 메모리 관리와 동적 할당

kid1412 2013. 5. 12. 19:49
728x90

I. C 언어의 메모리 구조

  • 스택(Stack), 힙(Heap)그리고 데이터(Data) 영역

    • 메모리 공간은 스택, 힙, 데이터영역으로 나뉘어 진다.

      • 할당 시기 : 프로그램이 실행될 때마다
      • 할당 장소 : 메인메모리인 RAM
      • 할당 용도 : 프로그램 실행 시 필요한 메모리 공간의 할당을 위해
    • 데이터 영역(Data Area)

      • 전역 변수와 static 변수가 할당되는 영역이다. 이 영역에 할당되는 변수들은 일반적으로 프로그래의 시작과 동시에 할당되고, 프고르매이 종료되어야만 메모리에서 소멸된다.
    • 스택 영역(Stack Area)

      • 지역변수와 매개 변수가 저장되는 영역. 이 영역에 할당된 변수는 함수 호출이 완료되면 사라진다는 특징이 있다.
    • 힙 영역(Heap Area)

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

 

  • 프로그램의 실행과 메모리의 흐름
  1.  #include <stdio.h>
  2. void fct1(int);
    void fct2(int);
  3. int a = 10;
    int b = 20;
  4. int main()
    {
     int m = 123;
  5.  fct1(m);
     fct2(m);
  6.  return 0;
    }
  7. void fct1(int c)
    {
     int d = 30;
    }
  8. void fct2(int e)
    {
     int f = 40;
    }
  •  위의 소스가 메모리 상에서 어떻게 되는지 밑의 그림을 보고 이해해 보자.

    • 첫 번째 : 프로그램의 시작 그리고 전역 변수의 저장
    • 001.jpg 

      • 원래는 프로그램의 시작은 main부터 이겠지만 메모리에서는 main 보다는 전역변수가 먼저 데이터 영역에 올라가는 것이 먼저다.
    • 두번째 : main 함수의 호출
    •  002.jpg

      • 지역 변수인 m이 선언과 동시에 123으로 초기화 되었다.
      • 지역변수 m은 main 함수 내에서 선언된 지역 변수이므로 main함수가 완료 되기 전까지만 유효할 것이다.
    • 세번째 : fct1 함수의 호출
    •  003.jpg

      • fct1 함수 호출되면서 인자 m을 전달한다.  전달된 m은 fct1의 매개변수인 c가 선언되면서 123으로 초기화 된다.
      • fct1 함수내에 있는 지역변수 d도 선언되면서 30으로 초기화 된다.
    • 네번째 : fct1함수의 완료 그리고 fct2 함수의 호출
    • 004.jpg 

      • fct1 함수가 완료 되면 fct2가 호출되고 있는데 fct1의 스택공간은 지워져 버리고 fct2의 스택 공간이 할당된다.
    • 다섯째 : fct2 함수의 완료, main 함수의 완료 그리고 프로그램의 완료
    •  005.jpg

      • 먼저 fct2가 완료 되면 스택공간에서 지워지고 그다음 메인이 끝나기 때문에 메인부분이 사라진다. 그리고 전역변수로 선언된 것이 지워지면서 프로그램은 종료된다.

 

  • 배열은 반드시 상수로 선언해야 하는 이유

    • 배열 선언은 반드시 상수를 사용한다.
  1. #include <stdio.h>
  2. void function(int);
  3. int main()
    {
     int m = 0;
     scanf("%d",&m);
     function(m);
  4.  return 0;
    }
  5. void function(int i)
    {
     int array[i];
    }
  • 위의 소스가 관연 될까?

    • 당연히 안된다. 배열을 선언 할때 변수를 쓰면 안된다.

 

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

    • 스택과 데이터 영역에 할당될 메모리의 크기는 컴파일되는 동안에 결정되어야 한다.
  1. void function(int a)
  2. {
  3. int b;
  4. int c[2];
  5. }
  • 위의 소스는 메모리에 얼마나 할당을 받아야 할까?

    • 4(int) + 8(int * 2) 총 12바이트를 받으면 된다.
  1. void function()
  2. {
  3. int i = 10;
  4. int array[i];
  5. }
  •  위의 소스는 메모리에 얼마나 할당을 받아야 할까?

    • 4 + 40 = 44바이트를 받으면 된다.
    • 하지만 컴파일러는 4 + 4 = 8바이트를 받게 된다. 

      • 이유는 int i = 10을 보고 int 형이구나 구만 생각을 한다 그래서 초기화에 대한건 생각을 안한다.

 

II. 메모리 동적 할당

  • malloc 함수 & free 함수

    • malloc 함수

      • #include<stdilb.h> void* malloc(size_t size) : 함수 원형이며 할당하고자 하는 메모리의 크기를 함수 호출 시 바이트 단위로 전달하면 그 크기만큼 메모리를 힙에 할당하게 된다.
    • free 함수

      • #include<stdlib.h> void free(void* ptr) : 해제하고자 하는 메모리 공간을 가리키는 포인터를 인자로 전달하면, 해당 포인터가 가리키는 메모리 공간을 해제한다.
  1.  #include <stdio.h>
    #include <stdlib.h>
  2. int main()
    {
     int* a;
     a = (int*)malloc(sizeof(int));
  3.  if(a==NULL)
     {
      puts("메모리 할당에 실패");
      exit(1);
     }
     *a = 20;
     printf("힙에 저장된 변수 a : %d\n",*a);
  4.  free(a);
     return 0;
    }
  • 위와 같이 사용을 한다.
  1.  #include <stdio.h>
    #include <stdlib.h>
  2. void function(int);
  3. int main()
    {
     int m =0;
     fputs("배열의 크기를 입력하세요 : ",stdout);
     scanf("%d",&m);
     function(m);
     return 0;
    }
  4. void function(int i)
    {
     int* array = (int*)malloc(sizeof(int)*i);
     int j;
     if (array == NULL)
     {
      puts("메모리 할당에 실패");
      exit(1);
     }
  5.  for(j=0;j<i;j++)
      array[j] = j+1;
     for(j=0;j<i;j++)
      printf("%d",array[j]);
     printf("\n");
     free(array);
    }
  • 위의 소스는 앞전에 변수를 받아서 사용자가 배열의 크기를 결정짓게 하겠다는 소스이다.

 

  •  calloc 함수

    • #include<stdlib.h> void *calloc(size_t elt_count, size_t elt_size) : 함수 원형이며

      • malloc과 같은 역할을 한다. 다만 calloc은 할당받으면서 초기화를 해준다고 한다.
Comments