211028, C언어 입문 day 12-2

Min Hyeok·2021년 10월 28일
0

C언어 개념 익히기

목록 보기
15/19

안녕하신가. 요즘 꾸준히 잘 출첵중이다.

이제 C언어 1회독이 거의 막바지다. 오늘 복습 좀 하고 백준 좀 풀고 남는 시간에 책 살거 슬슬 알아봐야할듯. 파이썬 공부용 책은 하나 있고, C++ / 자료구조 / 대학동기 추천 자료구조 문제집 이렇게 세권을 살까 생각중이다. 컴활은 지금 해야하나.. 조금 모르겠긴 한데, 이것도 해야할 것 같다고 생각중이고.

그리고 사실 일본어 공부하고 싶은데, 사람이 욕심만 많고 의지가 부족하다. 이걸 고쳐나가려고 꾸준히 공부하는것부터 습관을 들이는 중이고.

여튼, 오늘의 공부 시작하자.

16장 (- 2), 동적 메모리 할당

16-3

어제는 정적 메모리 할당에 대하여 알아봤다. 뭐 흔히 아는 변수들을 보고 정적 메모리 할당하는 방법 중 하나라고들 하죠.

근데 이 정적 메모리 할당이 사용은 쉬운데, 단점이 있다. 뭐 프로그래밍 공부하면 "쓰기 쉬운데에는 그만큼 제약과 한계가 있다"라고 하더라고. 그런 건가보지 머.

만약 컴파일러의 설정을 내가 따로 손대지 않는다면, 지역 변수가 저장되는 기본 Stack Memory의 크기는 1MB(1024Byte)다. 그래서 지역 변수가 할당되는 메모리 공간이 1MB가 넘을 수 없다고 한다.

만약

char data[1024 * 1024];

라고 set 한다면, 스택에 1MB가 할당되니까 오류가 발생하겠지.

그리고 프로그램이 사용하는 Stack의 크기는 실제로 프로그램이 실행되면서 함수가 호출될 때 까지 예측하기 어렵다. 즉, 내가 코드를 짜면서 이 크기를 미리 알고 그에 맞춰 메모리를 할당시킬 수 없다는 말이기도 하다.

그래서, 동적 메모리 할당을 써준다.

12-1일차에 그림 중 하나를 보면 Process를 세그먼트 3개로 분류했는데, 그 중 Stack segment를 보면 Heap(동적 메모리 할당)이 있다. 정적이랑은 다르게 프로그래머가 원하는 시점에, 원하는 크기만큼. 메모리를 할당할 수 있다. 그리고 GB까지 할당할 수 있어서 크기로 인해 문제가 발생할 일도 없음. 올 ㅋㅋ

이 동적메모리라는 좋은것을 쓸려고 한다면 <malloc.h>에 따로 저장되어 있는 malloc이라는 C 표준 함수를 따로 써줘서 메모리를 직접 할당해줘야한다. 이 함수는 메모리를 지정한 사이즈만큼 할당해서 그 할당된 주소를 void * 형식으로 반환해준다. 을마나 좋게요~~

void *p = malloc(100);

근데 저 100이 int형 25개인지, short형 50개인지 모르잖아? 그래서 void *형식으로 반환이 된다.

근데 저렇게 되면 할당된 공간을 쓸 때마다 Casting을 해줘야 한다. 그래서 처음부터 포인터 자체에 형 변환을 해놓는게 편함.

short *p = (short *) malloc(100);

이렇게. 이러면 대~충

저 100Byte 가 short 형 50개를 쓰려고 하니까 100Byte구나!

라고 알아챌 수 있다는 거지. 아니라고? 그러면 지금부터 그렇게 알아둬라.

지역 변수는 지 알아서 할당된 메모리 공간을 함수 호출이 끝나면 해제하는데, Heap은 그걸 알아서 못한다. 그럼 우리가 떠먹여주는 넉김으로 알아서 해제해줘야 하는데, 그건 free(p) 함수를 써줘야 한다.

만약 위의 예시 short *p 어쩌구를 동적 할당을 해줬다면 대충 프로그램 돌리고 마지막쯔음에

free(p);

요렇게, 메모리 해제를 해줘야한다. 만약 메모리 해제를 하지 않고 함수가 끝나버리면, 할당된 메모리의 주소를 기억하고 있는 포인터 변수 p 가 사라져버린다.

예를 들자면 뭐 알래스카에서 김상덕씨 찾기라는 미션이 있다면, 김상덕씨 주소를 알면 바로 찾아가서 김상덕씨죠? 아 네! 해서 찾으면 되는데, 주소를 적어놓은 노트를 잃어버렸다. 그 넓은 알래스카에서 어떻게 찾냐. 그 찾아다니는 시간을 어무청나게 손실하겠지.

이런식으로 free를 해주지 않으면 메모리 손실이 난다. 그래서 꼮꼮 free 함수를 넣어주도록 하자. 메손실 안나게. (메이플스토리 아님)

16.4

이 동적 메모리 할당을 어떻게 실제로 써먹을지 조금 난감한가?

사실 내가 처음 볼 때 그랬음 ㅋㅋ

자, 배열을 동적 메모리 할당으로 구현을 해보자.

만약 내가

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

이라고 저장했다.
이걸 어떻게 알아먹어야 할까?

포인터 변수 p가 가리키는 대상은 4바이트 크기다.. 근데 동적 할당은 16바이트다.. 4Byte * 4 = 16Byte다..

음..

int arr[4] 와 같아보이ㅣㅈ 않나?

그렇다. 배열처럼 쓸 수 있는것임.

"어 근데 배열은 arr[0], arr[1] 처럼 요소 빼서 쓸 수 있는데 저건 어케씀?"

앞서 언급한 적이 있다. 배열과 포인터를 섞어쓰는 방법에 대해.

*(p+0), *(p+1)

이렇게 써주면 된다.

근데 16이라 적어놓으면 좀 int형이 4개인 배열이라고 보려니 연관성이 크게 없어보이잖앙?

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

이렇게 써줘도 된다.

아니 배열 쓸 것을 굳이 왜 동적 메모리 할당을 함

이런 의문이 떠오를 수도 있다.

그동안 내가 백준 문제를 풀 때 조금씩 불편했던게

int size = 3;
int arr[size];

이런게 안 됐다. 배열 요소의 개수를 상수로만 할당할 수 있어서, 변수를 집어넣을 수가 없었다.

만약 내가 어떤 프로그램을 scanf로 입력을 받아서 사용자 임의로 어떤 요소의 개수를 설정해야한다고 치면, 저렇게 바로 배열을 만들어 버릴 수 없었다. 쓸모없이 오지게 크게 배열 만들어서 메모리 손실을 만들어버릴 수도 없고.

이런 단점을 없애려고 동적 메모리 할당을 써주는 것이다. 알간? ㅋㅋ

이렇게~ 16장도 끝났다.

오늘은, 여기까지.

0개의 댓글