[CS50] 메모리 - 메모리 교환, 스택, 힙

TIL

각각 사이다와 콜라가 들어있는 컵 두 개가 있을 때, 사이다와 콜라를 바꿔 담고 싶으면 어떻게 해야 할까?

아마 교환을 도와줄 새로운 컵이 잠시 필요할 것이다. 메모리에 저장된 값들을 교환할 때도 이와 비슷하게 할 수 있을까?

잘못된 값 교환

다음 코드를 보자.

#include <stdio.h>

void swap(int a, int b);

int main(void)
{
    int x = 1;
    int y = 2;

    printf("x is %i, y is %i\n", x, y);
    swap(x, y);
    printf("x is %i, y is %i\n", x, y);
}

void swap(int a, int b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
// 출력
// x is 1, y is 2
// x is 1, y is 2

 

swap 함수를 거친 후에도 x와 y의 값이 바뀌지 않았다. 교환하는 대상이 x, y 그 자체가 아닌 함수 내에서 새롭게 정의된 a, b이기 때문이다.

 

a, b는 각각 x와 y의 값을 복제하여 가지게 되며, 서로 다른 메모리 주소에 저장된다.

 

메모리 구조

메모리 안에는 다음과 같이 데이터가 저장되는 구역이 나뉘어져 있다.

 

메모리 영역

머신 코드 (Machine Code)

  • 프로그램이 컴파일된 바이너리 저장
  • 실행 가능한 명령어들

 

글로벌 (Globals)

  • 프로그램 안에서 선언된 전역 변수 저장
  • 프로그램 실행 내내 유지

 

힙 (Heap)

  • malloc으로 할당된 메모리의 데이터 저장
  • 동적으로 할당/해제 가능
  • 위쪽으로 증가 ↑

 

스택 (Stack)

  • 프로그램 내의 함수와 지역 변수 저장
  • 함수 호출 시 생성, 종료 시 소멸
  • 아래쪽으로 증가 ↓

 

스택 영역의 변수들

위의 코드에서 a, b, x, y, tmp 모두 스택 영역에 저장되지만, 서로 다른 위치에 저장된다.

스택:
┌──────────────┐
│ main 함수    │
│ x = 1        │ ← 주소 0x100
│ y = 2        │ ← 주소 0x104
├──────────────┤
│ swap 함수    │
│ a = 1        │ ← 주소 0x200 (x의 복사본)
│ b = 2        │ ← 주소 0x204 (y의 복사본)
│ tmp = 1      │ ← 주소 0x208
└──────────────┘

a와 b를 바꾸는 것은 x와 y를 바꾸는 것에 아무런 영향을 미치지 않는다.

 

올바른 값 교환

이 문제를 해결하려면 a와 b를 각각 x와 y를 가리키는 포인터로 지정하면 된다.

#include <stdio.h>

void swap(int *a, int *b);

int main(void)
{
    int x = 1;
    int y = 2;

    printf("x is %i, y is %i\n", x, y);
    swap(&x, &y);
    printf("x is %i, y is %i\n", x, y);
}

void swap(int *a, int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
// 출력
// x is 1, y is 2
// x is 2, y is 1

이제 값이 제대로 교환된다.

 

동작 원리

스택:
┌──────────────┐
│ main 함수    │
│ x = 1        │ ← 주소 0x100
│ y = 2        │ ← 주소 0x104
├──────────────┤
│ swap 함수    │
│ a = 0x100    │ ← x의 주소를 가리킴
│ b = 0x104    │ ← y의 주소를 가리킴
│ tmp = 1      │
└──────────────┘
  • tmp = *a → tmp에 x의 값(1) 저장
  • *a = *b → x의 위치에 y의 값(2) 저장
  • *b = tmp → y의 위치에 tmp의 값(1) 저장

 

값 전달 vs 포인터 전달

값 전달 (Call by Value)

void swap(int a, int b)
{
    int tmp = a;
    a = b;
    b = tmp;
    // 복사본만 바뀜
}

swap(x, y);  // x, y는 바뀌지 않음
  • 값을 복사하여 전달
  • 원본 변수에 영향 없음
  • 안전하지만 교환 불가능

 

포인터 전달 (Call by Reference)

void swap(int *a, int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
    // 원본이 바뀜
}

swap(&x, &y);  // x, y가 바뀜

 

  • 주소를 전달
  • 원본 변수 직접 수정 가능
  • 교환 및 수정 가능

 

스택과 힙 비교

특성 스택 (Stack) 힙 (Heap)
할당 방식 자동 수동 (malloc)
해제 방식 자동 (함수 종료) 수동 (free)
크기 제한적 (보통 수 MB) 상대적으로 큰 편
속도 빠름 느림
데이터 지역 변수, 매개변수 동적 할당 데이터
성장 방향 아래로 ↓ 위로 ↑
높은 주소
┌──────────────┐
│   스택 ↓     │ ← 함수 호출마다 증가
├──────────────┤
│   (빈 공간)  │
├──────────────┤
│   힙 ↑       │ ← malloc 호출마다 증가
├──────────────┤
│   글로벌     │
├──────────────┤
│  머신 코드   │
└──────────────┘
낮은 주소

 

연습 문제

Q. 메모리 영역을 다양하게 나누는 이유는 무엇일까?

각각의 기능과 역할을 분리해 프로그램을 효율적으로 운영하기 위해서다.

 

구체적인 장점

  1. 효율적인 메모리 관리
    • 스택: 빠른 할당/해제, 자동 관리
    • 힙: 큰 데이터, 유연한 수명 관리
  2. 보안
    • 머신 코드 영역을 읽기 전용으로 보호
    • 스택과 힙 분리로 오버플로우 공격 방어
  3. 데이터 수명 관리
    • 글로벌: 프로그램 전체 수명
    • 스택: 함수 수명
    • 힙: 프로그래머가 제어
  4. 최적화
    • 스택 (빠른 접근): int x = 10;
    • 힙 (큰 데이터, 긴 수명): int *arr = malloc(1000000 * sizeof(int));
  5. 동시성
    • 각 스레드가 독립적인 스택 보유
    • 힙은 공유 가능

 

메모리 영역별 용도

영역 용도 예시
머신 코드 실행 명령 컴파일된 함수들
글로벌 전역/정적 변수 int count = 0; (전역)
힙 동적 할당 malloc, free
스택 지역 변수/함수 호출 함수 내 변수들

 

실제 예시

#include <stdlib.h>

int global = 100;  // 글로벌 영역

int main(void)     // 머신 코드 영역
{
    int local = 10;              // 스택
    int *dynamic = malloc(40);   // 힙

    free(dynamic);
    return 0;
}

 

결론
메모리 영역을 나누면 각 데이터의 특성에 맞게 최적화된 관리가 가능하며, 안전하고 효율적인 프로그램 실행을 보장한다.

'TIL' 카테고리의 다른 글

React로 사용자 입력 관리하기  (0) 2025.11.08
[CS50] 메모리 - 파일 입출력  (0) 2025.11.08
[CS50] 메모리 - 메모리 할당과 해제  (0) 2025.11.08
[CS50] 메모리 - 문자열 복사  (0) 2025.11.08
[CS50] 메모리 - 문자열 비교  (0) 2025.11.07
'TIL' 카테고리의 다른 글
  • React로 사용자 입력 관리하기
  • [CS50] 메모리 - 파일 입출력
  • [CS50] 메모리 - 메모리 할당과 해제
  • [CS50] 메모리 - 문자열 복사
고견
고견
개발 자국 남기기
  • 고견
    개발자국
    고견
  • 전체
    오늘
    어제
    • 분류 전체보기 (157) N
      • Frontend (29)
        • Next.js (16)
        • JavaScript (7)
      • CS (19) N
        • 자료구조 (9)
        • 알고리즘 (5)
        • 운영체제 (4) N
        • 네트워크 (1) N
      • TIL (93)
      • Dev Log (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Trouble Shooting
    typescript
    C
    자료구조
    배열
    useState
    ai 감성 일기장
    인터페이스
    react
    Next.js
    알고리즘
    앱 라우터
    generic
    javascript
    바닐라 자바스크립트
    App Router
    트러블 슈팅
    함수 타입
    페이지 라우터
    클래스
    Spa
    제네릭
    타입 좁히기
    algorithm
    memory
    문자열
    Pages Router
    cs50
    emotion diary
    CS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고견
[CS50] 메모리 - 메모리 교환, 스택, 힙
상단으로

티스토리툴바