ptr[i] 문법)T**)가 필요한 대표 상황(포인터 자체를 바꾸기 / 동적 2D)Swapptr + 1이 실제로는 “주소 + sizeof(T)”라는 걸 설명할 수 있다.pp → *pp → **pp 접근을 말로 설명할 수 있다.hp + 1은 “값”이 1 증가합니다.ptr + 1은 “값”이 아니라 가리키는 위치가 이동합니다.핵심 규칙:
T* ptr에 대해 ptr + 1은 다음 T 한 칸으로 이동합니다.예: int가 4바이트라면, int* 포인터는 보통 4바이트 단위로 이동합니다.
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // arr[0]을 가리킴
ptr = ptr + 1; // arr[1]을 가리킴
*ptr = 999; // arr[1]이 999로 바뀜
(int*)100) 연산하는 건 정의되지 않은 동작(UB) 이고,int numbers[100]에서 numbers는 대부분의 식(expression)에서 첫 원소 주소로 변환(decay) 됩니다.int* ptr = numbers;가 가능합니다.numbers[3]*(numbers + 3)ptr[3] (단, ptr이 numbers를 가리키고 있을 때)int numbers[5] = {1, 2, 3, 4, 5};
int* ptr = numbers;
ptr[3] = 666; // numbers[3]을 666으로 변경
*(ptr + 1) = 777; // numbers[1]을 777로 변경
numbers 자체는 “포인터 변수”가 아닙니다. 그래서 아래는 불가능합니다.numbers = numbers + 1; (배열은 대입 대상이 아님)sizeof(numbers)는 “포인터 크기”가 아니라 배열 전체 크기가 나옵니다.int numbers[5] = {1, 2, 3, 4, 5};
int* ptr = numbers;
// 같은 대상 접근
numbers[2] = 100; // (1) 배열 인덱스
*(ptr + 2) = 200; // (2) 포인터 연산 + 역참조
ptr[2] = 300; // (3) 포인터 인덱싱
이중 포인터는 “포인터를 가리키는 포인터”입니다.
int** pp는 “어딘가에 int*가 있다”고 가정하고 접근합니다.pp : int*의 주소를 담는다*pp : 그 주소로 가서 int*(포인터)를 꺼낸다**pp: 그 포인터가 가리키는 int 값에 접근한다개념 그림:
pp ──▶ p ──▶ a(10)
(*pp) (**pp)
대표 사용처:
int* p = ...;를 함수에서 새 주소로 바꾸기)int a = 10;
int* p = &a;
int** pp = &p;
std::cout << **pp << '\n'; // 10
void Swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int a = 12, b = 20;
Swap(&a, &b);
// a=20, b=12
}
int* ptr에서 ptr + 1이 “주소 + 1”이 아닌 이유는?numbers와 ptr 중에서 “대입 가능(변수)”은 어느 쪽일까?pp, *pp, **pp는 각각 무엇을 의미할까?