포인터

김뉴오·2025년 4월 22일

키워드

목록 보기
6/15
post-thumbnail

포인터(Pointer)

  • 메모리 주소를 저장하는 변수
  • 어떤 변수의 위치를 가리킴 (값이 아니라 주소)

int a = 10;
int* p = &a;
코드의미
a정수형 변수, 값은 10
&aa의 메모리 주소
pa의 주소를 저장하는 포인터
*pp가 가리키는 주소에 있는 값 = a

메모리

[a] = 10
[p] = 주소 -> [a]

이중 포인터 (Double Pointer)

  • 포인터를 가리키는 포인터
  • 주소의 주소를 저장
int a = 10;
int* p = &a;
int** pp = &p;
설명
ppp의 주소 저장
*ppp의 값 (a의 주소)
**ppa의 값 (10)

사용 예시

  1. 포인터를 함수 인자로 전달
  2. 동적으로 2차원 배열 생성

함수와 포인터

  • 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]과 동일
*arrarr[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]

arrint (*)[3] 타입 → 포인터지만 정확히는 "행을 가리키는 포인터

  • arr[1]2] Arr[1][2]에 접근하는 것과 같은 것
    1. (*(Arr + 1) + 2)
    2. (&Arr[0][0] + 6)
    3. (Arr[1] + 2)
    4. (*(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바이트라고 가정):

주소설명
100010arr[0]
100420arr[1]
100830arr[2]
101240arr[3]
101650arr[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);  // ❌ 정의되지 않은 동작 (쓰면 안 됨)
profile
Bello! NewOld velog~

0개의 댓글