포인터는 결국 주소(address) 를 담는 변수다. 주소는 숫자이므로, 덧셈, 뺄셈, 비교 연산 등 다양한 연산이 가능하다. 포인터 연산은 주소값을 이동하면서 연결된 데이터에 접근하는 방법이다.
int a = 10;
int *p = &a;
printf("%p\n", p); // 주소 출력
printf("%d\n", *p); // 값 출력
✅ p + 1 은 1을 더하는 게 아니다
int arr[3] = {10, 20, 30};
int *p = arr;
printf("%d\n", *(p + 1)); // 20
p + 1 은 주소에 +4 (int 크기만큼) 더하는 것과 같다.
즉, 다음 요소를 가리키는 포인터가 된다.
| 자료형 크기를 기준으로 움직인다는 게 핵심이다.
✅ 뺄셈 연산
int arr[5] = {1, 2, 3, 4, 5};
int *p1 = &arr[4];
int *p2 = &arr[1];
int diff = p1 - p2; // 3
printf("%d\n", diff); // 배열에서 3칸 떨어져 있음
포인터끼리 뺄 수 있다.
두 포인터가 같은 배열 안에 있을 경우, 몇 칸 차이나는지(int 단위) 를 반환한다.
int arr[5] = {10, 20, 30, 40, 50};
printf("%d\n", *(arr + 2)); // 30
printf("%d\n", arr[2]); // 30
arr[i] 는 곧 *(arr + i) 와 같다.
배열의 이름 자체가 포인터처럼 쓰인다는 의미다.
그래서 포인터도 배열처럼 접근할 수 있다.
int *p = arr;
printf("%d\n", p[3]); // 40
int arr[3] = {100, 200, 300};
int *p = arr;
printf("%d\n", *p); // 100
p++; // 다음 요소로 이동
printf("%d\n", *p); // 200
p++ 는 다음 요소를 가리키도록 포인터를 이동시킨다.
p-- 는 이전 요소로 이동한다.
| 주의: 배열 범위를 벗어나면 정의되지 않은 동작(undefined behavior)이 발생한다.
| 연산 | 의미 |
|---|---|
p + i | i번째 요소를 가리킴 |
p - i | i만큼 이전 요소 가리킴 |
p1 - p2 | 배열 내 두 포인터 간 거리 (int 단위) |
p++ / p-- | 다음 또는 이전 요소로 이동 |
*p | 현재 가리키는 값 |
p[i] | *(p + i) 와 동일 |
int a = 42;
int *p = &a;
int **pp = &p;
printf("%d\n", **pp); // 42
이중 포인터도 결국은 주소를 담는 포인터다.
마찬가지로 pp++, pp + 1, *pp = q 같은 연산이 가능하다 (단, 할당된 메모리에 따라 조심해야 함).