security
CHAPTER 89 / 96
읽기 약 2분
FUNCTION
스택과 힙: 메모리 영역 이해
핵심 개념
코드/데이터/BSS/힙/스택 5개 영역 — 지역 변수(스택) vs malloc(힙). 스택 오버플로우의 원리.
본문
프로세스 메모리 5개 영역
┌──────────────────┐
│ 스택 (Stack) │ ← 지역 변수, 함수 호출
├──────────────────┤
│ ↓ │
│ │
│ ↑ │
├──────────────────┤
│ 힙 (Heap) │ ← malloc 동적 할당
├──────────────────┤
│ BSS Segment │ ← 초기화 안 된 전역
├──────────────────┤
│ Data Segment │ ← 초기화된 전역/static
├──────────────────┤
│ Code (Text) │ ← 컴파일된 함수 코드
└──────────────────┘ 낮은 주소각 영역의 변수
#include <stdio.h>
#include <stdlib.h>
int global_init = 100; // Data
int global_uninit; // BSS
void func(void) {
int local = 1; // Stack
static int s = 5; // Data (한 번만 초기화)
int *heap = malloc(16); // Heap
free(heap);
}
int main(void) {
func();
return 0;
}스택 — 함수 호출 프레임
#include <stdio.h>
void inner(void) {
int x = 10;
printf("inner: x = %p\n", (void*)&x);
}
void outer(void) {
int y = 20;
printf("outer: y = %p\n", (void*)&y);
inner();
}
int main(void) {
int z = 30;
printf("main: z = %p\n", (void*)&z);
outer();
return 0;
}
// 출력 (스택은 보통 높은 주소→낮은 주소로 자람):
// main: z = 0x7ffd1238
// outer: y = 0x7ffd1218 ← 더 낮은 주소
// inner: x = 0x7ffd11f8 ← 더 낮은 주소스택 프레임 시각화
[main 호출]
스택:
┌─────────────┐
│ return addr │ ← main 호출자의 다음 명령
│ saved %rbp │ ← 이전 프레임 포인터
│ z = 30 │
└─────────────┘
[outer 호출]
스택:
┌─────────────┐
│ ...main 데이터... │
├─────────────┤
│ return addr │ ← main 함수 안의 다음 명령
│ saved %rbp │
│ y = 20 │
└─────────────┘
[함수 종료]
- return addr 사용해 호출자로 복귀
- 스택 포인터 복구
- 지역 변수 사라짐스택 오버플로우 — 무한 재귀
#include <stdio.h>
void recursive(int depth) {
char buffer[1024]; // 1KB씩 스택 사용
printf("depth = %d\n", depth);
recursive(depth + 1); // ⚠️ 종료 조건 없음
}
int main(void) {
recursive(0);
// 출력: depth=0, 1, 2, ... 수천 번 후 SIGSEGV
// 스택 한도 (보통 8MB) 초과 → 세그폴트
return 0;
}힙 — 동적 할당
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// 런타임에 크기 결정
int n;
printf("배열 크기 입력: ");
if (scanf("%d", &n) != 1 || n <= 0) {
return 1;
}
// 힙에 할당
int *arr = malloc(n * sizeof(int));
if (arr == NULL) {
fprintf(stderr, "메모리 부족\n");
return 1;
}
for (int i = 0; i < n; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr); // ⚠️ 반드시 free
arr = NULL; // 다시 사용 방지
return 0;
}스택 vs 힙 비교
| 측면 | 스택 | 힙 |
|---|---|---|
| 할당 | 자동 (함수 호출 시) | 수동 (malloc) |
| 해제 | 자동 (함수 종료) | 수동 (free) |
| 속도 | 매우 빠름 | 느림 |
| 크기 | 작음 (보통 1~8MB) | 큼 (수 GB) |
| 수명 | 함수 범위 | 명시적 free까지 |
| 수정 | 컴파일 시 결정 | 런타임 가능 |
| 단편화 | 없음 | 있음 |메모리 영역 확인
#include <stdio.h>
#include <stdlib.h>
int gi = 1; // Data
int gu; // BSS
const int gc = 5; // Read-only
int main(void) {
int local = 10; // Stack
static int s = 20; // Data
int *h = malloc(16); // Heap
printf("Code (main): %p\n", (void*)main);
printf("Read-only (gc): %p\n", (void*)&gc);
printf("Data (gi): %p\n", (void*)&gi);
printf("BSS (gu): %p\n", (void*)&gu);
printf("Static (s): %p\n", (void*)&s);
printf("Heap (h): %p\n", (void*)h);
printf("Stack (local): %p\n", (void*)&local);
free(h);
return 0;
}다음 챕터
CH.6 "malloc과 free" — 동적 메모리의 전체 생명 주기.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 C 코드의 변수 사용을 분석해서 스택/힙 적절성과 메모리 폭주 가능성을 보고해줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
한국 임베디드 시스템(스택 64KB) 메모리 관리 사례 5가지를 비교해줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 C 코드에서 큰 지역 변수 + 깊은 재귀를 자동 탐지해서 힙 변환 가이드를 만들어줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 GCC stack-protector 옵션과 실무 활용 트렌드를 솔직히 알려줘.
⭐ 이것만 기억하세요
스택과 힙: 메모리 영역 이해는 이 3가지만 확실히 잡으세요
1.5개 메모리 영역: Code/Data/BSS/Heap/Stack — 변수의 위치가 수명·크기·속도 결정
2.스택은 빠르고 자동 (함수 범위), 힙은 느리고 수동 (명시적 free 필요)
3.다음 챕터 CH.6에서 malloc/free 동적 메모리 관리의 전체 생명 주기
공유하기
진행도 89 / 96