공부했던 자료 정리하는 용도입니다.
재배포, 수정하지 마세요.
메모리 구조
- 코드 영역(Code Area)
- 데이터 영역(Data Area)
- 스택 영역(Stack Area)
- 힙 영역(Heap Area)
동적 할당
- 힙 영역 메모리 공간 할당과 해제
* malloc
* calloc
* 할당된 메모리 공간 해제 : free
- 포인터 증가, 감소 연산과 메모리 해제
* 힙에 할당된 메모리 공간 확장 : realloc - memset 함수
메모리 구조
프로그램 실행 시 운영체제에 의해 마련되는 메모리의 구조는 다음과 같이 네 개의 영역으로 구분이 된다.
- 코드 영역(Code Area)
실행할 프로그램의 코드가 저장되는 메모리 공간. CPU는 코드 영역에 저장된 명령문들을 하나씩 가져가서 실행한다. - 데이터 영역(Data Area)
전역 변수와 static 변수가 할당된다. 프로그램의 시작과 동시에 메모리에 할당되어 프로그램 종료 시까지 남아있다. main 함수가 호출되기 이전에 데이터 영역이 먼저 초기화되고, (return문이 실행되어) 프로그램이 종료된 이후에 운영체제에 의해 할당된 메모리 공간 전체를 반환하는데, 이때가 전역 변수가 소멸하는 시점이다. - 스택 영역(Stack Area)
지역변수와 매개변수가 할당된다. 함수를 빠져나가면 소멸한다. - 힙 영역(Heap Area)
``malloc``, ``calloc``, ``realloc``함수를 통해 동적 할당되는 메모리들이 있는 공간
동적 할당(dynamic allocation)
``malloc``, ``calloc``, ``realloc``함수의 호출을 통한 메모리 공간의 할당을 가리켜 동적 할당이라고 한다. 메모리 크기를 컴파일러가 결정하지 않고, 프로그램의 실행 중간에 호출되는 함수가 결정하기 때문이다.
힙 영역의 메모리 공간 할당과 해제
힙 영역에 할당하는 메모리는 프로그래머가 원하는 시점에 할당하고 소멸시킬 수 있다. 동적 메모리 할당 (dynamic memory allocation)이라고 부른다. 메모리와 관련된 함수는 `stdlib.h`헤더에 선언되어 있다.
■ malloc
#include <stdlib.h>
void * malloc(size_t size) // size(byte)크기의 메모리 공간을 힙 영역에 할당
// 성공하면 메모리 주소를 반환, 실패하면 NULL을 반환
// 사용예시(주소값을 반환하기 때문에 포인터 변수로 접근해야한다.)
void * ptr = (int *)malloc(sizeof(int)); // 포인터변수 ptr이 malloc함수를 통해 할당된 메모리의 첫번째 byte를 가리킴
free(ptr) // 사용한 뒤 꼭 메모리를 해제해야한다.
// malloc함수는 메모리 할당에 실패할 경우 NULL을 반환하기 때문에 if문으로 함수의 호출 여부를 확인하기도 한다.
int * ptr = (int *)malloc(sizeof(int));
if(ptr == NULL)
{
// 메모리 할당 실패에 따른 오류의 처리
}
인자로 전달된 정수값에 해당하는 byte크기의 메모리 공간을 힙 영역에 할당한다. 함수 호출에 성공하면 할당된 메모리의 주소 값을, 실패하면 ##NULL##을 반환한다. @@malloc@@함수로 할당된 메모리는 프로그래머가 직접 @@free@@ 함수의 호출을 통해 해제하지 않으면 메모리에 계속 남아있기 때문에 주의한다.
- 주소 값을 반환하기 때문에 포인터 변수를 사용해야 하는데, 이렇게 하면 해당 포인터 변수가 ``malloc`` 함수 호출로 인해 할당된 메모리의 첫 번째 byte를 가리키게 된다.
- 함수의 반환형이 @@void@@형 포인터기 때문에 주소값을 형변환해야 메모리에 접근할 수 있다.
``void * ptr = malloc(sizeof(int))`` : 할당할 메모리 크기는 알지만 몇 byte씩 접근해야 하는지 모르기 때문에 접근 불가
##int * ptr = (int *)malloc(sizeof(int));##
##double * ptr = (double *)malloc(sizeof(double) * 7);## - @@malloc@@함수와 @@free@@함수의 호출 위치 및 시점에는 제한이 없다.
- @@calloc@@함수와 다르게 할당된 메모리 공간을 별도의 값으로 초기화하지 않는다.
■ calloc
#include <stdlib.h>
void * calloc(size_t elt_count, size_t elt_size);
``malloc`` 함수와 다르게 인자가 두 개이고, 할당된 메모리 공간의 모든 비트를 @@0@@으로 초기화시킨다.
함수 호출에 성공하면 할당된 메모리의 주소 값을, 실패하면 ##NULL##을 반환한다.
- ``elt_count`` : 할당할 블록의 개수 정보
- ``elt_size`` : 블록 하나당 byte 크기의 정보
■ 할당된 메모리 공간 해제 : free
#include <stdlib.h>
void free(void *_Block); // 힙 영역에 할당된 메모리 공간 해제
free(포인터);
변수는 스택(stack)에 생성되며 malloc 함수는 힙(heap) 부분의 메모리를 사용한다. 스택에 생성된 변수와 달리 힙에서 할당한 메모리는 반드시 해제를 해주어야 한다. 메모리를 해제하지 않아서 메모리 사용량이 계속 증가하는 현상을 메모리 누수(memory leak)라 부른다.
- 포인터 증가, 감소 연산과 메모리 해제
동적 메모리를 할당받은 포인터를 ``++``. ``--``포인터연산을 하게되면 포인터에 저장된 메모리 주소 자체가 바뀌게 된다. 이때 free 함수에서 메모리 주소가 바뀐 포인터로 메모리 해제를 하면 에러가 발생하므로 주의한다. (free 함수로 메모리 해제를 할 때는 반드시 처음에 메모리를 할당할 때 받은 주소를 넣어야한다.)
■ 힙에 할당된 메모리 공간 확장 : realloc
#include <stdlib.h>
void * realloc(void * ptr, size_t size);
// 사용예시
arr = (int *)realloc(arr, sizeof(int) * 5); // 길이가 5인 int형 배열로 확장
힙에 할당된 메모리 공간을 확장할 때 사용하는 함수이다.
함수 호출 성공 시 새로 할당된 메모리 주소 값을, 실패하면 ##NULL##을 반환한다.
- ``ptr`` : 확장하고자 하는 힙 메모리의 시작 주소 값
- ``size`` : 확장하고자 하는 메모리의 전체 크기
realloc을 사용했을 때 발생하는 경우의 수
- 기존에 할당된 메모리 공간의 뒤에 확장할 영역이 넉넉한 경우
→ malloc 함수가 반환한 주소 값과 realloc 함수가 반환한 주소 값이 같다. - 기존에 할당된 메모리 공간의 뒤에 확장할 영역이 부족한 경우
→ malloc 함수가 반환한 주소 값과 realloc 함수가 반환한 주소 값이 다르다.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int * ptr1 = (int *)malloc(sizeof(int)); // 포인터변수 ptr1이 malloc함수를 통해 할당된 메모리의 첫번째 byte를 가리킴
int * ptr2 = calloc(5, sizeof(int)); // calloc으로 4byte * 5 크기의 동적메모리 할당
int i;
ptr2 = realloc(ptr2, sizeof(int) * 7); // ptr2가 가리키는 메모리를 길이가 7인 int형 배열로 확장
*ptr1 = 20;
for(i = 0 ; i < 7 ; i++)
ptr2[i] = i + 1;
printf("%d \n", *ptr1);
for(i = 0 ; i < 7 ; i++)
printf("%d ", ptr2[i]);
free(ptr1);
free(ptr2);
return 0;
}
동적 할당에 관련된 함수를 사용하는 예시이다.
6행의 ``malloc``함수는 반환하는 주소 값을 ``int *``형으로 형 변환했기 때문에 메모리에 접근할 수 있다.
memset (memory set)
memset(포인터, 설정할 값, 크기);
void *memset(void *_Dst, int _Val, size_t _Size);
// 값 설정이 끝난 포인터를 반환
// 사용 예시
long long *numPtr = malloc(sizeof(long long));
memset(numPtr, 0, sizeof(long long)); // numPtr이 가리키는 메모리의 long long 크기만큼 0으로 설정
- 메모리의 내용을 원하는 크기만큼 특정값으로 설정할 수 있다.
- string.h헤더에 선언되어 있다. (memory.h헤더를 포함해도 사용가능)
- 메모리의 내용을 모두 0으로 만들 때 주로 사용한다.
'기타 > C' 카테고리의 다른 글
[C] 파일의 분할, 헤더파일 (0) | 2020.06.17 |
---|---|
[C] 매크로와 선행 처리기(Preprocessor) (0) | 2020.06.16 |
[C] 공용체(Union Type), 열거형(Enumerated Type) (0) | 2020.06.08 |
[C] 구조체 (0) | 2020.06.01 |
[C] 문자, 문자열 (0) | 2020.05.28 |