포인터란 무엇일까?
포인터는 집 주소와 같은 것, 즉 집에는 고유한 주소가 있듯(서울시 어쩌구)
모든 변수들도 메모리의 저장되므로 주소가 필요하다.
다시 정리해서 말하자면, 메모리 주소는 각 데이터가 저장된 위치의 고유 번호이다.
포인터는 이 주소를 기억하는 변수(메모장 역할)이다.
그렇다면 주소를 따라가서 실제 데이터를 가지고 올 수 있나?
라는 생각을 할텐데, 당연히 가능하고 이를 역참조라고 부른다.
메모리 구조 시각화
메모리 주소 변수명 저장된 값
1000 number 42
1004 ptr 1000 (number의 주소)
1008 other 100
여기서 ptr은 number의 주소인 1000을 저장하고 있다.
포인터 선언과 초기화
기본 문법
#include <iostream>
using namespace std;
int main() {
int number = 42; // 일반 변수
int* ptr = &number; // 포인터 변수 (number의 주소를 저장)
cout << "number의 값: " << number << endl;
cout << "number의 주소: " << &number << endl;
cout << "ptr이 저장하는 주소: " << ptr << endl;
cout << "ptr이 가리키는 값: " << *ptr << endl;
return 0;
}
중요한 연산자들
- & (주소 연산자): "~의 주소를 알려줘"
- (역참조 연산자): "이 주소에 있는 값을 알려줘"
초보자 실수 방지 팁
int* ptr1, ptr2; // 주의! ptr1만 포인터, ptr2는 일반 int
int *ptr3, *ptr4; // 둘 다 포인터 (권장하지 않음)
int* ptr5; // 명확한 포인터 선언 (권장)
int* ptr6;
포인터 연산의 특별한 규칙
포인터 산술의 핵심 개념
일반적인 숫자 계산과 달리, 포인터 연산은 데이터 타입의 크기를 고려한다.
#include <iostream>
using namespace std;
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // 배열의 첫 번째 원소를 가리킴
cout << "ptr이 가리키는 값: " << *ptr << endl; // 10
cout << "ptr의 주소: " << ptr << endl;
// 포인터 증가 - 중요한 개념!
ptr++; // 다음 int 위치로 이동 (4바이트 증가)
cout << "ptr++ 후 값: " << *ptr << endl; // 20
cout << "ptr++ 후 주소: " << ptr << endl;
// 포인터 + 숫자
ptr = arr; // 다시 처음으로
cout << "ptr + 2의 값: " << *(ptr + 2) << endl; // 30
return 0;
}
왜 이렇게 동작할까?
- int는 4바이트를 차지함.
- ptr + 1은 메모리 주소를 4바이트 증가.
- char*라면 1바이트, double*라면 8바이트씩 증가.
실습: 값 교환 함수
#include <iostream>
using namespace std;
// 잘못된 방법 - 값 복사
void swapWrong(int a, int b) {
cout << "swapWrong 함수 내부에서:" << endl;
cout << "교환 전: a=" << a << ", b=" << b << endl;
int temp = a;
a = b;
b = temp;
cout << "교환 후: a=" << a << ", b=" << b << endl;
// 하지만 원본 변수는 바뀌지 않음!
}
// 올바른 방법 - 포인터 사용
void swapCorrect(int* a, int* b) {
cout << "swapCorrect 함수 내부에서:" << endl;
cout << "교환 전: *a=" << *a << ", *b=" << *b << endl;
int temp = *a;
*a = *b;
*b = temp;
cout << "교환 후: *a=" << *a << ", *b=" << *b << endl;
// 원본 변수가 실제로 바뀜!
}
int main() {
int x = 10, y = 20;
cout << "=== 원본 값 ===" << endl;
cout << "x = " << x << ", y = " << y << endl;
cout << "\\n=== 잘못된 교환 시도 ===" << endl;
swapWrong(x, y);
cout << "함수 호출 후: x = " << x << ", y = " << y << endl;
cout << "\\n=== 올바른 교환 ===" << endl;
swapCorrect(&x, &y);
cout << "함수 호출 후: x = " << x << ", y = " << y << endl;
return 0;
}
왜 이런 차이가 생길까?
- 값 전달: 변수의 복사본을 함수에 전달 → 원본 변경 불가
- 포인터 전달: 변수의 주소를 함수에 전달 → 원본 변경 가능
포인터 디버깅 팁
포인터 값 확인하기
#include <iostream>
using namespace std;
int main() {
int number = 100;
int* ptr = &number;
cout << "=== 포인터 정보 확인 ===" << endl;
cout << "number 변수의 값: " << number << endl;
cout << "number 변수의 주소: " << &number << endl;
cout << "ptr 변수가 저장하는 주소: " << ptr << endl;
cout << "ptr 변수 자체의 주소: " << &ptr << endl;
cout << "ptr이 가리키는 값: " << *ptr << endl;
// 포인터 유효성 확인
if (ptr != nullptr) {
cout << "포인터가 유효한 주소를 가리키고 있습니다." << endl;
}
return 0;
}
초보자 주의사항
1. 초기화되지 않은 포인터
int* ptr; // 위험! 쓰레기 값을 가지고 있음
// *ptr = 10; // 런타임 에러 발생 가능
int* safePtr = nullptr; // 안전한 초기화
2. 잘못된 포인터 연산
int number = 42;
int* ptr = &number;
// 올바른 사용
cout << *ptr << endl; // 42 출력
// 잘못된 사용
// cout << ptr + 100 << endl; // 의미 없는 주소
3. 포인터와 배열의 혼동
int arr[3] = {1, 2, 3};
int* ptr = arr; // 올바름: 배열 이름은 첫 번째 원소의 주소
// arr++; // 오류! 배열 이름은 상수
ptr++; // 올바름: 포인터는 변경 가능
정리
핵심 개념 요약
- 포인터: 메모리 주소를 저장하는 변수
- & 연산자: 변수의 주소를 구함
- 연산자: 주소에 있는 값을 가져옴
- 포인터 연산: 데이터 타입 크기만큼 증가/감소
- 함수 인자: 포인터로 전달하면 원본 수정 가능
반응형
'Game DevTip > C++' 카테고리의 다른 글
12. C++ 배열에 대해서 (1) | 2025.07.16 |
---|---|
11. C++ 참조자에 대하여 (0) | 2025.07.15 |
9. 비트 연산과 Bitflag, Bitmask에 대해서 (4) | 2025.07.09 |
8. C++로 GameObjectPool을 구현 해보자. (1) | 2025.05.21 |
7. C++ friend, 동적메모리 관리, 클래스 상속에 대해서 알아보자. (0) | 2025.05.21 |
댓글