메모리 구조


프로그램이 실행되면, 프로세스가 된다. OS는 프로세스가 작업을 수행하는데 사용할 수 있는 메모리를 제공한다. 메모리의 저장 공간은 세분화하여 5가지 영역으로 나뉘어져 있다.



1. 코드 영역(Code segment)

프로그램을 실행하면, 프로그램 파일( .exe)의 내용이 여기에 저장된다. 이 영역에 저장된 내용을 변경할 수 없고, 읽기만 가능하다. 나머지 영역들은 읽기와 쓰기가 모두 가능하다.




2. 데이터 영역(Data segment)

전역 변수와 정적 변수(static)가 할당되는 영역이다. 초기화된 전역변수는 Data영역에 할당되고 초기화 되지 않은 전역변수는 BSS에 할당되어 0으로 초기화 된다.




3. BSS 영역(Block Stated Symbol)

초기화 되지 않은 전역변수가 할당되어 0으로 초기화 된다.


1
2
3
4
5
6
7
8
9
#include<stdio.h>
int a = 3//Data 영역
int b; //BSS영역
int main() {
 
    int c; //Stack 영역
    printf("%d %d %d\n", a, b, c); // 3 0 쓰레기 값 
    return 0;
}
cs


int a = 3//Data 영역
int b; //BSS영역
int c; //Stack 영역



4. Stack 영역

함수가 작업을 수행하는데 사용하는 메모리 공간이다. 함수가 호출되면 스택에 호출된 함수를 위한 메모리가 할당되며, 이 메모리는 함수가 작업을 수행하는 동안 지역 변수를 저장하는데 사용된다.

그리고 함수가 작업을 마치면 할당되었던 메모리는 반환되어 해당 함수의 지역변수는 자동으로 메모리에서 제거된다.



5. Heap 영역

프로그램 실행 중에 동적으로 메모리를 할당받아 사용할 수 있는 영역이다. 필요할 때 할당 받아서 사용하고, 다 사용한 후에는 반환 할 수 있다. 힙은 스택과 달리 자동으로 메모리가 반환되지 않으므로, 동적할당 받은 메모리는 사용 후에 반드시 메모리를 반환하는 함수를 호출해야 한다.



5-1. 동적할당

함수 내에 지역적으로 선언된 변수나 배열은 합수가 종료되면 메모리에서 사라지기 때문에 여러 함수에서 사용하기에 부적합 하다. 그렇다고 전역적으로 선언된 변수나 배열은 여러 함수에서 사용하기 좋지만 프로그램이 종료될때까지 메모리를 점유해서 메모리 공간을 비효율 적으로 사용하게 된다. 필요할 때만 메모리를 할당받아 사용하기 위한 방법이 바로 동적할당이다.


동적 메모리 할당 : 실행 중에 원하는 기간 동안 필요한 만큼의 메모리를 할당받는 것


malloc( ) 

동적으로 메모리를 할당 받으려면 malloc( ) 이라는 함수를 사용해야 하는데  이 함수를 호출하면 메모리 할당 요청이 OS에게 전달된다. 그러면 OS는 힙(heap)에서 사용중이지 않은 영역을 찾아 할당해준다. 할당 받은 메모리는 사용한 후에 free( )를 호출해서 반환한다.


사용법은 이러하다.

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
#include<stdlib.h>
int main() {
    //동적 할당받은 공간의 주소를 포인터 pi에 저장
    int* pi = (int*)malloc(sizeof(int)); 
    //동적 할당받은 공간에 값을 저장
    *pi = 10;
    //동적 할당받은 공간에 저장된 값을 출력
    printf("%d\n"*pi);
free(pi);
    system("pause");
    return 0;
}
cs

동적으로 할당받은 저장공간은 오직 포인터를 통해서만 접근할 수 있다.

ex)   *(p+0) = 1;

       *p = 1;

  p[0] = 1;

위 세줄은 모두 같은 의미이다.



malloc( )의 반환값은 타입이 'void*' 이므로, 이 값을 어떠한 타입의 포인터에 저장해도 된다. = 할당 받은 공간을 어떠한 용도로든 자유롭게 사용할 수 있다.

동적으로 할당받은 공간은 주로 배열로 쓰인다. 그리고 이 공간을 배열로 사용하는 것은 배열을 포인터로 다루는 것과 완전히 동일하다. 



memset 

힙도 스택처럼 초기화 없이 덮어쓰기만 하므로 malloc( )을 통해 할당받은 메모리는 이전 데이터 값(쓰레기 값)이 그대로 남아있다. 초기화가 필요하면, memset로 초기화 할 수있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
    //동적 할당받은 공간의 주소를 포인터 pi에 저장
    int* pi = (int*)malloc(sizeof(int)); 
    //동적 할당받은 공간을 0으로 초기화
    memset(pi, 0sizeof(int));
    //동적 할당받은 공간에 초기화된 값을 출력
    printf("%d\n"*pi);
free(pi);
    system("pause");
    return 0;
}
fㄹcs




free( ) 

동적으로 할당받은 메모리는 사용한 후에 반드시 할당을 해제해야 한다. 그렇지 않으면 메모리 누수가 발생한다. 또한 free( )를 한 후에 해당 메모리에 접근하는 댕글링 포인터를 조심해야한다.


*메모리 누수 : 프로그램에 메모리를 할당 후, 해제하지 않아서 시스템의 메모리를 고갈시키는 소프트웨어 오류

*댕글링 포인터 : 해제된 메모리를 가리키는 포인터


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
    //동적 할당받은 공간의 주소를 포인터 pi에 저장
    int* pi = (int*)malloc(sizeof(int)); 
    //동적 할당받은 공간을 0으로 초기화
    memset(pi, 0sizeof(int));
    //동적 할당받은 공간에 초기화된 값을 출력
    printf("%d\n"*pi);
    //동적 할당받은 공간의 사용이 다하면 메모리를 해제
    free(pi);
    system("pause");
    return 0;
}
cs



calloc( ) 

calloc( )은 다음과 같이 정의 되어 있다.

void *calloc(size_t n , size_t size) ;


calloc은 매개변수가 2개 이다. 타입의 크기와 개수를 따로 받는다.


iArr = malloc(100 * sizeof(int));

iArr = calloc(100, sizeof(int));


위의 두 문장은 모두 int타입의 값을 100개 저장할 수 있는 메모리를 할당받는다.

(malloc 과 calloc의 차이점은 calloc은 malloc과 다르게 할당받은 메모리는 모두 0으로 자동 초기화 된다)



realloc( ) 


동적 할당받은 메모리가 부족하게 된 경우에는 추가로 malloc을 사용할 수도 있지만 두 메모리의 주소가 연속적이라는 보장이 없기 때문에 사용하는데 어려움이 있다. 그래서 이럴땐 realloc( )을 사용하면 된다.


realloc은 다음과 같이 정의 되어 있다.

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


첫 번째 매개변수 :동적 할당받은 메모리의 주소

두 번째 매개변수 :변경하고자 하는 메모리의 크기

첫 번째 매개변수의 값이 NULL이면 malloc과 같은 역할을

두 번째 매개변수의 값이 0이면 free( )처럼 동작하여 해당 메모리는 해제된다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
    int* Arr;
    Arr = (int*)malloc(sizeof(int* 10);
    *(Arr + 5= 10;
    printf("%d %d\n",Arr[5],Arr[15]);
    //동적할당된 Arr의 크기가 10이어서 10을 넘으면 쓰레기 값이 출력된다.
    Arr = (int*)realloc(Arr, sizeof(int* 10 * 2);
    //기존의 동적할당 되었던 Arr의 크기를 2배로 늘리고 값을 할당하였다.
    Arr[15= 10;
    printf("%d  %d\n"*(Arr+5),Arr[15]);
    system("pause");
    return 0;
}
cs


'@C언어 : Layer7' 카테고리의 다른 글

구조체 예제  (0) 2018.05.15
구조체  (0) 2018.05.13
Codeup 100제  (0) 2018.04.13
문자열 함수 구현  (0) 2018.04.11
함수 문제풀이  (0) 2018.04.09

+ Recent posts