chapter 22
메모리 관리와 메모리의 동적 할당
C언어의 메모리 구조: Code(코드), Data(데이터), Stack(스택), Heap(힙)
메모리를 나누는 이유: 메모리 공간을 나눠서 유사한 성향의 데이터를 묶어서 저장을 하면,
관리가 용이해지고 메모리의 접근 속도가 훨씬 향상되기 때문에 4가지 영역 Code,Data,Stack,Heap으로 나눈다.
-
Code(코드) 영역 실행할 프로그램의 코드가 저장되는 메모리 공간이다. CPU는 코드 영역에 저장된 명령문들을 하나씩 가져가서 실행을 한다.
-
Data(데이터) 영역 전역변수와 static으로 선언되는 static 변수가 할당된다. 이 영역에 할당된 변수들은
프로그램의 시작과 동시에 메모리 공간에 할당되어 프로그램 종료 시까지 남아 있는 특징이 있다. -
Stack(스택) 영역 스택에는 지역변수와 매개변수(Parameter)가 할당된다. 이 변수들은 함수가 호출될때 생성되고,
함수가 종료될때 소멸되는 특징이 있다.
(중요)
함수의 호출, 반환, 지역변수의 호출, 반환과 같은 경우는 자료구조 stack과 같은 움직임을 보인다.[FIFO]
따라서 이 영역의 이름이 stack 인 거고 여기에 지역변수나 매개변수가 할당되는 것이다. -
Heap(힙) 영역 함수가 호출될때 할당되고, 함수가 종료되어도 유지가 되는 변수들이 이 구역에 할당된다.
이 변수들은 malloc과, free라는 함수를 통해 힙(heap) 영역에 할당되고 소멸할 수 있다.
이를 동적할당이라 한다.
메모리의 동적 할당
- 동적 할당을 쓰는 이유: 함수를 빠져나갈때 소멸되지 않는 변수를 사용하기 위해(전역 변수 제외)
:특정 함수의 지역변수는 함수를 빠져나갈때 소멸되므로, 밖에서는 쓸 수 없다.
또 함수 밖으로 나가도 쓸수 있는 전역변수는 또 다시 사용하면 값이 유지가 안되기에 사용이 부적절하다.
따라서 함수 밖에서도 소멸되지않고, 또 값이 독자적으로 유지되는 변수가 필요한데, 그 변수가 바로
동적할당된 변수이다. malloc()을 통해 변수에게 동적으로 메모리를 할당해주고, 소멸시키고 싶을때 free()을 사용하여 개발자
마음대로 소멸시킬수 있는 변수, 동적할당된 변수가 바로 함수를 빠져나가도 소멸되지 않는 적절한 변수이다.
- 힙(heap)의 메모리 공간 할당과 해제 : malloc 과 free 함수
## include <stdio.h>
void * malloc(size_t size); // 힙(heap) 영역으로의 메모리 공간 할당
void free(void* ptr); // 힙(heap) 영역에 할당된 메모리 공간 해제
// malloc 함수는 성공 시 할당된 메모리의 주소값, 실패시 NULL 반환.
=> 자료형이 void* 인 이유: 동적할당할 변수의 자료형이 어떻게 될지 모르기에 void로 둔것이다.
이는 개발자가 casting으로 자료형을 변환시켜 주면 되는데 ,만약 하지 않으면 void으로는 주소값만 할당될 뿐,
변수를 이용해 사용할 수 없으므로 반드시 casting 해야 함을 명심하자.
=> free 함수를 안쓰면?: 사실 free 함수를 안써도 프로그램이 종료되면 힙영역의 동적할당된 변수들도 소멸되기 때문에 메모리에 끝까지
남지 않는다.
하지만 free()를 안쓰면 복잡한 프로그램을 짤때 메모리 관련하여 무수한 에러가 생길 수 있으므로
동적할당을 선언했으면 반드시 free() 함수를 쓰도록 하자.
동적할당을 안 써서 오류 난 경우
## include <stdio.h>
## include <stdlib.h>
## define len 30
char* readname(void){
char name[len];
printf("이름 입력: ");
fgets(name,len,stdin);
return name; // 이러면 문제가 되는게 name이 지역변수이므로 함수가 종료될 때 name도 소멸된다.
// 그런데 반환은 name의 주소값이므로 아무리 main에 name의 주소값이 반환되더라도
// name은 소멸되었므로 참조해도 오류가 난다. 그래서 세그멘테이션 오류가 나는 것이고(혹은 null 반환),
// 이럴 때 malloc으로 동적할당하여 함수가 끝나도 사라지지않는 변수를 사용해야 하는 것이다.
}
int main(void){
char* name1;
name1=readname();
printf("%s", name1);
return 0;
}
동적할당하여 제대로 된 경우
## include <stdio.h>
## include <stdlib.h>
## define len 30
char* readname(void){
char* name=malloc(sizeof(char)*len);
printf("이름 입력: ");
fgets(name,len,stdin);
return name;
}
int main(void){
char* name1;
name1=readname(); // 동적할당을 하여 name이라는 변수가 힙에 계속남아있으므로 name1이 name의 주소값을 잘 반환받아,
// 에러 없이 성공적으로 문자열을 출력할수 있다.
printf("%s", name1);
free(name1);// name,name1의 메모리 공간 해제
return 0;
}