int a = 10;
int* p = &a;
| 코드 | 의미 |
|---|---|
a | 정수형 변수, 값은 10 |
&a | a의 메모리 주소 |
p | a의 주소를 저장하는 포인터 |
*p | p가 가리키는 주소에 있는 값 = a |
메모리
[a] = 10
[p] = 주소 -> [a]
int a = 10;
int* p = &a;
int** pp = &p;
| 식 | 설명 |
|---|---|
pp | p의 주소 저장 |
*pp | p의 값 (a의 주소) |
**pp | a의 값 (10) |
사용 예시
Call by Value vs Call by Reference
일반 전달
void set(int x) {
x = 100;
}
→ main의 변수에는 영향 없음 (복사)
void set(int* p) {
*p = 100;
}
→ main의 변수에 직접 접근 가능
void setPtr(int** pp) {
static int b = 200;
*pp = &b;
}
→ 포인터 자체의 대상 변경 가능
1차원 배열
int arr[3] = {1, 2, 3};
| 표현 | 의미 |
|---|---|
arr | &arr[0]와 동일 |
*(arr + 1) | arr[1]과 동일 |
*arr | arr[0] 와 동일 |
2차원 배열
int arr[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
| 표현 | 의미 |
|---|---|
arr == &arr[0] | |
arr[0] == &arr[0][0] | |
**arr == arr[0][0] | |
*arr == arr[0] |
arr은 int (*)[3] 타입 → 포인터지만 정확히는 "행을 가리키는 포인터
Arr[1][2]에 접근하는 것과 같은 것(*(Arr + 1) + 2) (&Arr[0][0] + 6) (Arr[1] + 2) (*(Arr) + 6) ❌ ← 이건 Arr[0][6]이야Arr + 1 == &Arr[1](Arr + 1) == Arr[1] == &Arr[1][0](*(Arr + 1) + 2) == Arr[1][2]메모리 구조 그림
---
p + n)포인터에 정수 n을 더하면, n개의 요소만큼 이동함
(요소란 자료형 기준, 예: int는 4바이트니까 p + 1은 4바이트 뒤로)
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
*(p + 2) == 30; // arr[2]를 의미
p - n)정수만큼 뒤로 감
int* q = p + 3; // arr[3]
*(q - 2) == arr[1] == 20;
p1 - p2)두 포인터가 같은 배열 내에 있을 경우, 인덱스 차이를 계산할 수 있음
int* p = &arr[4]; // arr[4]
int* q = &arr[0]; // arr[0]
int diff = p - q; // 결과: 4
!!!단, 다른 배열을 가리키는 포인터끼리는 뺄 수 없음. (정의되지 않은 행동)
int arr[5] = {10, 20, 30, 40, 50};
메모리 구조 (int는 4바이트라고 가정):
| 주소 | 값 | 설명 |
|---|---|---|
| 1000 | 10 | arr[0] |
| 1004 | 20 | arr[1] |
| 1008 | 30 | arr[2] |
| 1012 | 40 | arr[3] |
| 1016 | 50 | arr[4] |
포인터 p = arr이면 → *p = 10, *(p+1) = 20, *(p+2) = 30
배열은 포인터처럼 작동해!
즉, 배열 이름 arr은 &arr[0]와 같다.
int arr[5] = {10, 20, 30, 40, 50};
arr[i] == *(arr + i)
이걸 잘 이해하면 배열과 포인터의 관계를 쉽게 풀 수 있어.
| 자료형 | 포인터 증가 시 이동 크기 |
|---|---|
char* | 1바이트 |
int* | 4바이트 (보통) |
double* | 8바이트 |
struct | 구조체 크기만큼 |
예:
char c[3] = {'a', 'b', 'c'};
char* cp = c;
printf("%c", *(cp + 1)); // b
double d[2] = {1.1, 2.2};
double* dp = d;
printf("%lf", *(dp + 1)); // 2.2
배열을 함수로 넘길 때도 포인터 연산은 핵심이야.
void printArr(int* p, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", *(p + i)); // 또는 p[i]
}
}
p++, p-- 연산포인터 변수 자체를 한 칸 옮겨주는 연산
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
printf("%d\n", *p); // 10
p++;
printf("%d\n", *p); // 20
p = arr + 5; // arr[5]는 실제 값 없음
printf("%d", *p); // ❌ 정의되지 않은 동작 (쓰면 안 됨)