크래프톤 정글 5~8주차 탐험준비
c는 참 멋있는 언어다. 정글에선 c언어를 f1 레이싱카로 비유한다.
"C언어는 F1 레이스 카와 비슷하다. 그 무엇보다도 빠르고 성능 좋지만, 아무나 운전할 수 없고, 아무나 운전하도록 두어서도 안된다."
지금까지 배워왔던 알고리즘을 C로 구현하는 한주가 되고, malloc, RB-tree, 웹서버 구현등을 해야한다
불편하고 빠르게 달려보자
1. 포인터란?
*를 사용해 해당 주소의 값을 읽는 c언어의 연산자이다.
포인터를 왜 사용하는가에 대해서는
여러가지가 존재하지만 이해하기 쉬운 예를 하나 들자면
c언어에서는 값에 의한 참조와 주소에 의한 참조가 존재한다.
#include <stdio.h>
void increment(int num) {
num++;
printf("함수 내 num: %d\n", num);
}
int main() {
int a = 10;
increment(a);
printf("함수 호출 후 a: %d\n", a);
return 0;
}
이런 경우에 a값은 여전히 10이 나온다.
a의 값을 복사해서 넣어준 것 이기 때문에
함수 안에서는 새로운 값이 만들어지기 때문에 원래있던 a와는 관계가 없기때문에
#include <stdio.h>
void increment(int *num) {
(*num)++;
printf("함수 내 num: %d\n", *num);
}
int main() {
int a = 10;
increment(&a);
printf("함수 호출 후 a: %d\n", a);
return 0;
}
이런 경우에는 주소에 의한 호출이 일어나서 함수안에 있는 num은
기존에 있던 a의 주소를 참조하고 있기 때문에
이때 a의값은 11이 된다.
이렇게 주소를 사용할 때 c언어에서는 * 와 & 연산자를 사용한다.
2. 주소연산자란?
주소 연산자란 변수 앞에 & 키워드를 붙여 메모리주소를 반환하는 연산자이다.
int *ptr = &x; 이런식으로 사용한다면
x의 메모리주소를 ptr에 저장하고, *ptr 을 사용하면 해당 주소의 값을 참조한다.
그럼 이것들은 언제 많이 사용하는가?
- scanf 계열 함수
- 입력받은 데이터를 저장하려면 해당주소를 함수에게 알려주어야 하기 때문에
&를 필수적으로 사용한다.
- 입력받은 데이터를 저장하려면 해당주소를 함수에게 알려주어야 하기 때문에
- 함수에서 값 변경/반환
- 이 경우엔 리턴하지 않아도 주소를 참조하고 있는 포인터의 값을 넣어줄 수 있기 때문에 편리하다.
- 큰 데이터 효율적 전달
- 복사없이 주소로만 연산
- 동적 메모리 할당(중요)
- 동적으로 메모리를 할당 시 메모리를 지정해줘야 한다
- 자료구조 구현
이 외에도 많이 사용하겠지만
여러가지 함수, 기능을 작성하면서 익히는 것이 효율적일 것이라 생각된다.
자료구조, 이중포인터는 감도 안잡힌다..
c 프로그래밍은 값 전달만 지원하기 때문에
포인터를 꼭 사용해야 한다.
3. 동적 메모리 할당이란?
포인터의 연장선으로 동적으로 메모리를 할당하는 malloc 함수가 있다.
이 함수의 기능은 힙 영역에 동적으로 메모리를 할당해
유연하고 효율적으로 메모리를 관리할 수 있다.
스택의 메모리 양은 매우 적고,
힙은 상대적으로 매우 크다.
그렇다면 다 힙에 저장하면 되지 않나?
성능차이가 매우 크게 난다.
스택은 low-level에서 봤을 때 매우 간단한 처리를 한다.
(스택레지스터 변경)
그에 비해 힙은 블록리스트 검색, 크기 검사, 블록 분할, 메타데이터 업데이트, 주소 정렬, 포인터 반환 ..
수십~수백개의 cpu명령어를 내려야 하고, 메타데이터로 메모리양도 증가한다.
그 외 캐시미스 등 여러가지 이유에서 두 자료구조의 속도차이가 크게 난다.
그래서 malloc 어떻게 사용하고, 언제 사용?
| 상황 | 스택 | 힙 |
|---|---|---|
| 간단한 변수 | ✅ | ❌ |
| 작은 배열 (<1KB) | ✅ | ❌ |
| 큰 배열 (>10KB) | ❌ | ✅ |
| 크기 미리 알 수 있음 | ✅ | ❌ |
| 크기 런타임 결정 | ❌ | ✅ |
| 성능이 중요 | ✅ | ❌ |
| 함수 밖으로 전달 | ❌ | ✅ |
사용법
int *ptr = (int*)malloc(sizeof(int));
if (ptr != NULL) { // NULL 체크
*ptr = 10;
// ... 사용 ...
free(ptr); // 반드시 해제
ptr = NULL; // NULL로 설정
}
malloc, free 주의점
메모리를 할당했으면 꼭 해제해줘야 한다.
불필요하게 메모리를 사용하면서 메모리누수가 발생하고,
이는 점차 프로그램이 망가지기 시작한다.
하지만 스택도 막 사용한다면 스택오버플로우가 발생하면서
프로그램은 바로 망가진다.
즉 천천히 말라죽는것이 힙메모리영역
단번에 죽는것이 스택영역이다.
'Develop' 카테고리의 다른 글
| malloc lab-implicit list에 관하여 + 구현 (3) | 2025.08.23 |
|---|---|
| Red-Black Tree 개념 (3) | 2025.08.15 |
| Longest Common Subsequence (5) | 2025.08.04 |
| 위상정렬 Topological Sort (3) | 2025.07.29 |
| 우선순위 큐 (2) | 2025.07.23 |