2021. 10. 26. 21:49ㆍDiary/300~400
현재 시간 오후 7시 30분.
일하고 프린트 뽑고 집에 들어왔는데,
문득.. 오늘은 너무 쉬고 싶다는 생각이 든다.
이상하게 오늘따라 정신도 몽롱하고
열도 나는 것 같은 그런 느낌이어서 살짝 지쳤다.
하지만, 오늘 쉬면 분명 내일 후회한다.
이런 생각이 들고,
블로그에 간단한 글 하나 적는게 뭐가 어렵다고
왜 내가 계속 변명거리를 찾고있지..?
라는 생각이 들었다.
결국 지금 컴퓨터를 키고 책상 앞에 앉았다.
적어도 어제 얘기했던
malloc, free, stack, heap에 대해서
어느정도 공부를 하고 누워야겠다.
우선 malloc에 대해서 검색해봤다.
< C 동적 메모리 할당 - 위키백과 >
C 동적 메모리 할당은 동적 메모리 할당을 위한 수동 메모리 관리를 수행하는 것을 말하며 C에 담긴 malloc, realloc, calloc 그리고 free 등의 함수를 말한다. 메모리 동적 할당을 위한 포인터 변수를 선언하여 동적 할당을 하는 순간 일반 변수를 저장하는 stack이 아닌 heap에 저장되기 때문에 free로 동적 할당을 해제하지 않는 이상 메모리가 반납되지 않으며, 따라서 함수가 끝나더라도 메모리의 값은 유지된다. 그래서 C언어 교재나 강의에서 문자열, 구조체 주소를 반납하는 함수를 다룰 때 malloc 사용을 반드시 하거나, static을 사용하라고 한다.
뭔가 어려운 글자의 압박때문에
순식간에 피로감을 느낀다.
하지만.. 하나씩 꼼꼼히 읽어보자.
"C 동적 메모리 할당은"
"동적 메모리 할당을 위한 수동 메모리 관리를"
"수행하는 것을 말한다."
우선 동적이라는 말에 대해
생각해보자.
동적의 반대말은 정적이다.
우리가 파이썬을 하다보면 듣는 말이
파이썬(Python)은 동적 타이핑 언어라는 것이다.
그럼 정적 타이핑 언어는 무엇인가?
바로 C언어, 자바(Java)를 뜻한다.
하지만, 내가 처음 저 말을 접했을 때,
무슨 개소린가... 싶었다.
나도 암기하듯이 공부할 때는 이해를 못했다.
그렇지만, 막상 Python과 Java를 둘 다 접해보면
감이 온다.
우리가 파이썬을 하면서 가장 편한게 무엇인가?
바로 변수의 타입을 지정해 줄 필요가 없다는 것이다.
변수 X에 10이라는 값을 주고싶다.
그렇다면 파이썬과 자바에서의 차이점을 보자.
< Python >
X = 10
< Java >
int X = 10
동적과 정적 타이핑에서 발생하는 차이점은
이 뿐만이 아니다.
위의 상황에서 파이썬은 X에
문자열을 대입할 수 있다.
< Python >
X = 10
X = "문자열"
하지만, 자바는 위처럼 X = "문자열"을 적으면
에러가 나온다.
이유는 말한대로 동적, 정적 타이핑에서 나온다.
동적 타이핑은 변수의 타입을 동적으로
그때그때마다 바꿀 수 있다.
정적 타이핑은 변수의 타입을 지정해야하고,
그 타입에 맞는 값만을 넣어야 한다.
그렇다면 다시 문장을 읽어보자.
"C 동적 메모리 할당은"
"동적 메모리 할당을 위한 수동 메모리 관리를"
"수행하는 것을 말한다."
이제 동적, 정적에 대해서 파악했다.
그렇다면 메모리 할당이란 무엇인가?
사실, C언어에서 메모리 할당에 대해
확실하게 이해하기 위해서는 포인터를 공부해야한다.
포인터는 아래의 글을 참고하길...
https://kwonputer.tistory.com/6?category=890338
1일차 포인터란 무엇인가?
kwonputer.tistory.com
메모리 할당과 포인터를
쉽게 비유해서 설명하자면,
우리가 이사를 가야하는 상황이다.
가장 먼저 해야하는 일은
물건을 정리하는 일이다.
현재 내 집의 상태는 난장판이다.
옷이나 생필품들이 여기저기 널부러져있다.
그래서 일단 집 밖으로 나온다음
슈퍼에 가서 상자(Box)를
최대한 많이 가져왔다.
그 다음에 집에 도착해서
상자에 구분하기 위한 이름표를 붙였다.
상의, 하의, 신발, 모자, 생필품 등등
그 다음에 물건들을
하나하나 분류한 다음 상자에 넣었다.
짐을 아주 효율적으로 정리해서.
이사할 때, 원할하게 짐을 옮길 수 있었다.
여기서 상자들(Boxes)이 바로 메모리다.
메모리 할당은 상자에 모자 이름표를 붙이고
그 안에 모자를 넣는 것이다.
상자에 붙은 이름표는 포인터다.
우리가 모자를 찾기 위해서는
모자 이름표가 붙은 상자를 열어보면 된다.
이게 포인터의 역할이다.
내 물건이 어느 상자에 있는지 찾기 위한 역할.
일단 이는 쉽게 설명하기 위해
비유해서 설명한 것이다.
정확한 개념은 재미없는 위키백과를
참고하길 바란다..! 좀 고될것이다..!
후.. 아무튼 다시 문장을 읽어보자.
"C 동적 메모리 할당은"
"동적 메모리 할당을 위한 수동 메모리 관리를"
"수행하는 것을 말한다."
이제 어느정도 감이 오는가..?
C 언어는 정적 타이핑 언어이기 때문에
동적으로 데이터를 다루기 위해
동적 메모리 할당이 필요하다.
다만, 파이썬 처럼 자동으로 변수의 타입을
파악하는 것이 아니기 때문에.
개발자가 직접(수동) 메모리를 관리해야 한다.
개발자가 직접(수동) 메모리를 관리하기 위해서
malloc, realloc, calloc, free 등의
함수가 존재하는 것이다.
그 다음 글을 읽어보자.
"메모리 동적 할당을 위한 포인터 변수를 선언하여"
"동적 할당을 하는 순간,"
"일반 변수를 저장하는 Stack이 아닌"
"Heap에 저장되기 때문에"
"free로 동적 할당을 해제하지 않는 이상"
"메모리가 반납되지 않으며,"
"따라서 함수가 끝나더라도"
"메모리의 값은 유지된다."
자 하나하나 읽어보자.
메모리 동적 할당을 위한 포인터 변수를 선언.
이부분은 아까 비유했던 대로
상자(메모리의)에 이름표(주소값)을
붙이는 것이다.
그다음 문장을 읽어보자.
동적 할당을 하는 순간,
일반 변수를 저장하는 Stack이 아닌
Heap에 저장된다.
어제 내가 Stack과 Heap대해서
Stack은 책을 쌓는 것이고
Heap는 놀이기구의 줄을 서는 것이다.
라고 설명했다.
그렇다면, 이를 C 언어로 구현해보자.
일단 시간이 벌써 오후 9시라서
간단하게 오늘은 Stack만 해보자.
< Stack >
우선 Stack을 어떻게 구현할 것인지
생각해보자.
위의 이미지를 보면서 생각해보자.
1. 책을 넣기. (Push)
2. 책을 빼기. (Pop)
3. 책이 천장 높이까지
닿으면 그만 넣기. (Full)
4. 책의 개수 세기. (Count)
#include<stdio.h>
#include<stdlib.h>
#define STACK_SIZE 5 // 천장 까지 책을 쌓을 수 있는 개수.
char stack[STACK_SIZE]; // 책을 쌓을거라고 사서한테 말함.
int stack_last_data = -1; // 마지막에 쌓은 책. 가장 위에 있는 책.
// 책이 천장에 닿았는지 확인.
int check_stack() {
if(stack_last_data >= STACK_SIZE - 1) { // 마지막에 쌓은 책이 천장에 닿았을 경우.
printf("\n책이 천장에 닿았습니다. \n더 이상 책을 쌓지 못합니다.\n");
return 1;
}
return 0;
}
// 책 넣기.
void push(char data) {
printf("\n책 제목 [ %c ]를 쌓기 위해 시도합니다.\n", data);
if(!check_stack()) { // 책이 천장에 닿지 않았을 경우, 책을 넣는다.
stack_last_data++;
stack[stack_last_data] = data;
}
}
// 책 빼기.
void pop() {
if(stack_last_data == -1) { // 뺄 수 있는 책이 없다.
printf("\n책의 개수가 [ 0 ]개이기 때문에\n뺄 수 있는 책이 없습니다.\n");
} else { // 책을 뺀다.
char temp_stack = stack[stack_last_data];
stack_last_data--;
printf("\n책 제목 [ %c ]를 뺐습니다.\n", temp_stack);
}
}
// 현재 책 목록 파악.
void stack_count() {
if(stack_last_data == -1) { // 뺄 수 있는 책이 없는 경우.
printf("\n현재 책의 개수는 [ 0 ]개 입니다.\n");
} else {
int temp_stack_data = stack_last_data;
printf("\n현재 책의 개수는 [ %d ]개 입니다.\n", temp_stack_data + 1);
for(int k = 0; k <= stack_last_data; k++) {
printf("\n책 제목 [ %c ] ", stack[k]);
}
printf("\n");
}
}
int main() {
printf("\n ========== ========== ==========\n");
stack_count();
pop();
printf("\n ========== ========== ==========\n");
push('A');
push('B');
push('C');
stack_count();
printf("\n ========== ========== ==========\n");
push('D');
push('E');
stack_count();
printf("\n ========== ========== ==========\n");
push('F');
push('G');
stack_count();
printf("\n ========== ========== ==========\n");
pop();
pop();
stack_count();
}
< 결과 >
========== ========== ==========
현재 책의 개수는 [ 0 ]개 입니다.
책의 개수가 [ 0 ]개이기 때문에
뺄 수 있는 책이 없습니다.
========== ========== ==========
책 제목 [ A ]를 쌓기 위해 시도합니다.
책 제목 [ B ]를 쌓기 위해 시도합니다.
책 제목 [ C ]를 쌓기 위해 시도합니다.
현재 책의 개수는 [ 3 ]개 입니다.
책 제목 [ A ]
책 제목 [ B ]
책 제목 [ C ]
========== ========== ==========
책 제목 [ D ]를 쌓기 위해 시도합니다.
책 제목 [ E ]를 쌓기 위해 시도합니다.
현재 책의 개수는 [ 5 ]개 입니다.
책 제목 [ A ]
책 제목 [ B ]
책 제목 [ C ]
책 제목 [ D ]
책 제목 [ E ]
========== ========== ==========
책 제목 [ F ]를 쌓기 위해 시도합니다.
책이 천장에 닿았습니다.
더 이상 책을 쌓지 못합니다.
책 제목 [ G ]를 쌓기 위해 시도합니다.
책이 천장에 닿았습니다.
더 이상 책을 쌓지 못합니다.
현재 책의 개수는 [ 5 ]개 입니다.
책 제목 [ A ]
책 제목 [ B ]
책 제목 [ C ]
책 제목 [ D ]
책 제목 [ E ]
========== ========== ==========
책 제목 [ E ]를 뺐습니다.
책 제목 [ D ]를 뺐습니다.
현재 책의 개수는 [ 3 ]개 입니다.
책 제목 [ A ]
책 제목 [ B ]
책 제목 [ C ]
음.. Stack에 대해 대충은 감을 잡았는가..?
앞으로도 최대한 다른 사람에게
설명하기 쉽도록 코드를 짜보려고한다.
이렇게 하는게 이해도 쉽고
나한테도 도움이 될 것 같다.
시간이 벌써 오후 9시 48분이다.
얼른 밥을 먹고 누워야겠다.
내일은 Heap을 해보고
왜 Stack과 Heap이 필요한지 알아보는
글을 적어야겠다.
그 다음에는 Malloc와 Free를 알아봐야겠다.
오늘도 의식의 흐름대로 글을 마친다!
'Diary > 300~400' 카테고리의 다른 글
306일차 - 간단한 조사(AI, DL 설명 및 사용 기술) (0) | 2021.10.31 |
---|---|
305일차 - Stack, Heap, Malloc, Free (0) | 2021.10.30 |
304일차 - Kotlin Room을 활용한 간단한 게시판 만들기 (1) | 2021.10.29 |
303일차 - Android Room 정리 (0) | 2021.10.28 |
302일차 - 계획 수립 및 Android Room, 인공지능(AI), 딥러닝(DL) (0) | 2021.10.27 |