I. 포인터 (Pointer)
1) 포인터의 정의
- 변수의 메모리 주소를 저장하는 변수
int num = 10;
int* ptr = #
ptr에는 num의 주소가 들어 있음
2) 포인터를 사용하는 이유
① 큰 데이터를 복사하지 않아도 됨
- 값을 복사하면 데이터 크기만큼 복사 비용이 발생함
int → 4Byte
double → 8Byte
char → 1Byte
- int arr[1000000]; 과 같이 큰 배열을 복사하면 매우 비효율적임
- 포인터는 주소 하나(8Byte)만 전달하면 되어서 매우 빠름
② 원본 데이터를 직접 수정할 수 있음
int num = 10;
int* ptr = #
*ptr = 20;
결과: num == 20
3) 주소 연산자 (&)
- 변수의 주소를 얻음
int num = 10;
cout << #
결과: num의 주소가 출력됨
4) 역참조 연산자 (*)
- 포인터가 가리키는 실제 값을 읽거나 수정함
int num = 10;
int* ptr = #
cout << *ptr;
*ptr = 30;
cout << *ptr;
결과: 각각 10, 30 출력
5) 포인터 선언과 초기화
- 포인터 타입은 가리키는 변수의 타입을 의미함
int* p; //4Byte
char* p; //1Byte
double* p; //8Byte
- 포인터 타입을 알고 있어야 주소에서 몇 byte를 읽을 지 알 수 있음
int* ptr = nullptr; //아무 것도 가리키지 않음을 의미함
- 초기화 되지 않은 포인터는 예기치 않은 오류를 일으킬 수 있음
- 반드시 nullptr로 초기화하는 습관이 중요함
6) 포인터의 크기
- 포인터의 크기는 타입과 관계없이 모두 동일함
sizeof(int*)
sizeof(char*)
sizeof(double*)
- 모두 8Byte (64bit 운영체제 기준, 32bit 운영체제에서는 4Byte)
7) 배열과 포인터의 유사성
① 배열 이름은 첫 번째 원소의 주소를 의미함
int arr[3];
// arr == &arr[0]
② []는 포인터 연산과 같음
arr[2] == *(arr + 2)
arr[i] == *(arr + i)
③ 배열 이름은 변경할 수 없음
arr = other; //불가능
- 배열 이름은 상수 포인터처럼 동작함
- 배열 이름이 바뀌게 되면 원소에 임의접근 할 수 없음
8) 포인터 연산
- 포인터는 주소를 이동함
ptr + 1 //주소 이동
int* -> 4Byte 이동
char* -> 1Byte 이동
double* -> 8Byte 이동
9) 포인터 배열과 배열 포인터
① 포인터 배열
- 포인터를 여러 개 저장하는 배열
int a = 10, b = 20, c = 30;
int* ptrArr[3] = {&a, &b, &c};
cout << *ptrArr[0] << endl; //10 출력
cout << *ptrArr[1] << endl; //20 출력
cout << *ptrArr[2] << endl; //30 출력
메모리 구조
a = 10
b = 20
c = 30
┌──────┐
│ 10 │ ← a
└──────┘
┌──────┐
│ 20 │ ← b
└──────┘
┌──────┐
│ 30 │ ← c
└──────┘
ptrArr
┌────────┐
│ &a │
├────────┤
│ &b │
├────────┤
│ &c │
└────────┘
② 배열 포인터
- 배열 전체를 가리키는 포인터
int arr[3] = { 100, 200, 300 };
int (*ptr)[3] = &arr; // 배열 포인터 선언
cout << (*ptr)[0] << endl; //100 출력
cout << (*ptr)[1] << endl; //200 출력
cout << (*ptr)[2] << endl; //300 출력
메모리 구조
arr
┌──────┬──────┬──────┐
│ 100 │ 200 │ 300 │
└──────┴──────┴──────┘
^
|
ptr
- 주로 다차원 배열에서 사용함
int arr[3][4];
int (*ptr)[4] = arr;
10) 포인터 사용 정리
① 일반 변수를 포인터로 가리킬 때
int a = 5;
int* ptr = &a;
*ptr = 10; // a == 10
ptr -> 주소
*ptr -> 값
② 배열을 포인터로 받을 때
int arr[3] = {1, 2, 3};
int* ptr = arr; // ptr[i] == *(ptr + i)
arr은 &arr[0]으로 ptr에 주소를 전달하고 있음
ptr[0]은 이미 내부적으로 *가 들어있음 -> *ptr[0]을 하면, *(*(ptr+0))이 되어서 오류가 발생함
③ 포인터 배열
int a = 10;
int b = 20;
int c = 30;
int* ptr[3] = {&a, &b, &c};
ptr[0]의 타입은 int*
ptr[i] -> 주소
*ptr[i] -> 값
④ 배열 포인터
int arr[3] = {1,2,3};
int (*ptr)[3] = &arr;
ptr은 배열 전체를 가리키는 포인터
*ptr은 arr이 됨 -> (*ptr)[i]는 arr[i]이 됨
arr과 &arr의 차이
int arr = {1, 10, 100};
&arr[0] + 1 == 10을 가지는 주소를 가리킴 //int*라면 4byte만큼 이동함
&arr + 1 == 배열 밖의 주소를 가리킴 //int*라면 4byte * 3 해서 12byte만큼 이동함
가리키는 주소는 같지만, 포인터 연산을 할 때 차이가 남
II. 레퍼런스 (Reference)
1) 레퍼런스의 정의
- 기존 변수의 별명(Alias)
- 선언과 동시에 무조건 초기화해야함
int num = 10;
int& ref = num;
num과 ref는 같음
2) 값 변경
ref = 30;
cout << num << endl;
30이 출력됨
3) 포인터와 레퍼런스의 차이
| 포인터 | 레퍼런스 |
| 주소 저장 | 변수의 별명 |
| 재연결 가능 | 재연결 불가 |
| nullptr 가능 | nullptr 불가 |
| *,& 사용 | 일반 변수처럼 사용 |
포인터
int num = 10;
int* ptr = #
*ptr = 20;
레퍼런스
int num = 10;
int& ref = num;
ref = 20;
- 문법이 간단함
4) 상수 레퍼런스 (const reference)
- 읽기만 가능하고 수정은 불가능함
const int& ref = num;
cout << ref; // 가능
ref = 30; // 불가능
복사 비용 없이 데이터를 읽을 때 사용함
'언리얼 엔진 > 개념 정리' 카테고리의 다른 글
| 개념 정리 - C++ (상속, 다형성) (0) | 2026.07.17 |
|---|---|
| 개념 정리 - C++(클래스) (0) | 2026.07.10 |
| 개념 정리 - C++(조건문과 반복문) (0) | 2026.07.08 |
| 개념 정리 - C++(배열과 함수) (0) | 2026.07.08 |
| 개념 정리 - C++(변수와 입출력) (0) | 2026.07.08 |