이 Step에서 다루는 것

  • “복사 전달(Call by Value)”의 한계를 해결하기 위해 주소를 다루는 이유
  • 포인터의 2가지 핵심 연산자: &(주소 얻기), *(역참조/따라가기)
  • 포인터 타입이 왜 중요한지(크기/해석/메모리 오염)
  • 포인터가 위험해지는 대표 상황: 미초기화 / nullptr 역참조 / 댕글링(수명 끝)

학습 목표

  • 포인터를 한 문장으로 정의할 수 있다.
  • int* p = &x; *p = 10;이 의미하는 바를 말로 설명할 수 있다.
  • “원본을 바꾸려면 주소를 넘긴다”를 함수 예제로 재현할 수 있다.

포인터가 필요한 이유

  • AddHp(hp, 20)처럼 값을 넘기는 함수는 기본적으로 “복사본”을 받습니다.
  • 그래서 함수 내부에서 hp += 20;을 해도 main의 hp(원본) 은 바뀌지 않습니다.
  • 원본을 바꾸려면 “값”이 아니라 원본이 있는 위치(주소) 를 넘겨야 합니다.
    • 그 주소를 따라가서(역참조) 원본을 수정하는 문법이 포인터/참조입니다.

포인터의 정의

항목설명
개념메모리 주소를 담는 변수
크기32bit면 보통 4byte, 64bit면 보통 8byte (플랫폼/빌드에 따라 달라짐)
타입int* → “이 주소에 int가 있다고 가정하고 접근하겠다”는 약속
  • int* ptr;에서 ptrint의 주소를 담겠다는 의미입니다.
  • 주소도 결국 숫자처럼 보이지만, 의미는 “메모리 위치”이기 때문에 함부로 연산하면 위험합니다.
  • nullptr: “아무 것도 가리키지 않는다”는 의미의 값(현대 C++).
    • 숫자 0과 구분되는 의미라서, 가능하면 nullptr를 쓰는 습관이 좋습니다.

개념 그림(주소를 담고, 따라가서 값에 접근):

int hp = 100;
int* ptr = &hp;

ptr  ──(hp의 주소를 담음)──▶  hp(100)
*ptr ──(그 주소로 가서)────▶  hp의 값(100)

주소 연산자 &

  • &변수 → 해당 변수의 메모리 주소를 가져옴.
  • ptr = &hp → hp의 주소를 ptr에 저장.
int hp = 100;
int* ptr = &hp;  // hp의 주소를 ptr에 저장

역참조 (Dereference) *

  • *ptr → ptr이 가리키는 주소에 있는 값을 읽거나 수정합니다.
  • *ptr = 200 → 원본 hp가 200으로 바뀜.
int a = 10;
int* p = &a;
*p = 20;  // a의 값이 20으로 바뀜

실수 방지 규칙(필수)

  • ptrnullptr이거나 쓰레기 값이면 *ptr는 터질 수 있습니다.
  • 그래서 포인터는 항상 다음 중 하나가 되게 유지하는 습관이 중요합니다.
    • 유효한 주소를 가리킨다
    • 또는 nullptr이다(가리키는 대상 없음)

포인터 타입의 중요성

  • *ptr로 접근할 때 컴파일러는 “그 주소에 무엇이 있는지”를 포인터 타입으로 판단합니다.
  • 타입이 틀리면:
    • 값 해석이 깨지거나
    • 경우에 따라 인접 메모리까지 잘못 읽고/쓰게 되어 메모리 오염으로 이어질 수 있습니다.

메모리 오염은 “지금 안 터지고” 한참 뒤에 터질 수 있어서 디버깅 난이도가 급상승합니다.

int hp = 100;
float* fptr = (float*)&hp;  // int를 float처럼 해석 → 데이터 왜곡/버그 가능

위 같은 캐스팅은 학습 단계에서 “왜 위험한지”를 알기 위한 예시입니다.
실무에서는 이런 코드가 나오면 “정말 의도한 게 맞나?”부터 의심하는 게 일반적입니다.


AddHp 포인터 버전

void AddHp(int* hp, int value) {
    *hp += value;  // 주소 타고 가서 원본 수정
}

int main() {
    int hp = 100;
    AddHp(&hp, 10);
    std::cout << hp << '\n';  // 110
}
  • &hp로 주소 전달. *hp로 그 주소의 값을 직접 수정.
  • 스택 프레임 관점: AddHp의 매개변수에는 주소값이 복사되어 들어감. 그 주소를 따라가면 main의 hp 영역에 도달 → 원본 수정 가능.

안전 버전(널 체크 습관)

void AddHpSafe(int* hp, int value)
{
    if (hp == nullptr)
        return;

    *hp += value;
}

체크 질문 (스스로 답해보기)

  • 포인터의 크기는 “항상 8바이트”일까? 어떤 조건에서 달라질까?
  • int* p = &a;에서 p가 들고 있는 것은 “a의 값”인가 “a의 주소”인가?
  • *p = 20;이 실행되면 바뀌는 건 무엇인가?

profile
李家네_공부방

0개의 댓글