728x90
C 언어를 공부하다 보면 int **ptr, char **argv 같은 문장을 마주하게 됩니다. 이때 등장하는 것이 바로 **이중 포인터(double pointer)**입니다.
이중 포인터는 초심자에게 혼란을 주기 쉽지만, 그 개념을 제대로 이해하면 2차원 배열, 포인터 배열, 동적 메모리 할당, 함수 인자 전달 등 다양한 고급 C 문법을 훨씬 쉽게 다룰 수 있습니다.
🧠 이중 포인터란?
이름 그대로, 포인터를 가리키는 포인터입니다. 즉,
- 일반 포인터 int *p는 정수형 값을 가리키는 포인터이고,
- 이중 포인터 int **pp는 "정수형 포인터 p를 가리키는 포인터"입니다.
📌 예시 구조
int a = 10;
int *p = &a; // p는 a를 가리킴
int **pp = &p; // pp는 p를 가리킴
이 상태에서 각 변수는 다음을 의미합니다:
표현의미
a | 정수 값 10 |
p | 변수 a의 주소 |
*p | p가 가리키는 값 → 10 |
pp | 변수 p의 주소 |
*pp | pp가 가리키는 값 → p |
**pp | *pp가 가리키는 값 → 10 |
🔍 메모리 구조로 이해하기
변수 값 의미
-------- ---------- --------------------------
a 10 일반 정수 변수
p &a a의 주소를 저장 (int *)
pp &p p의 주소를 저장 (int **)
실제 메모리 주소가 있다고 가정하면:
주소 변수 값
-------- ------- ------------
0x1000 a 10
0x2000 p 0x1000
0x3000 pp 0x2000
*pp = p = &a, **pp = *p = a
📋 예제: 이중 포인터 선언과 사용
#include <stdio.h>
int main() {
int num = 10;
int *ptr = #
int **dptr = &ptr;
printf("num: %d\n", num); // 10
printf("*ptr: %d\n", *ptr); // 10
printf("**dptr: %d\n", **dptr); // 10
**dptr = 20;
printf("num after change: %d\n", num); // 20
return 0;
}
이 예제는 **dptr = 20;을 통해 이중 포인터로 원래 변수 값을 수정할 수 있다는 것을 보여줍니다.
✅ 즉, 이중 포인터는 원래 변수의 주소까지 '두 단계'를 거쳐 접근합니다.
🔄 함수에서의 활용: 포인터를 인자로 전달할 때
C에서는 값에 의한 호출(call by value) 방식이기 때문에 함수로 전달된 변수는 복사본입니다. 따라서 함수 내에서 포인터 자체를 바꾸려면 이중 포인터를 사용해야 합니다.
❌ 잘못된 방식 (단일 포인터)
void allocate(int *p) {
p = malloc(sizeof(int)); // 원래 포인터에는 영향 없음
*p = 42;
}
✅ 올바른 방식 (이중 포인터)
void allocate(int **p) {
*p = malloc(sizeof(int));
**p = 42;
}
int main() {
int *ptr = NULL;
allocate(&ptr);
printf("Allocated: %d\n", *ptr);
free(ptr);
return 0;
}
함수에서 메모리를 동적으로 할당하고 그 주소를 반환하려면 반드시 이중 포인터가 필요합니다.
🧭 언제 이중 포인터를 써야 할까?
상황 | 설명 |
포인터 자체를 변경해야 할 때 | 포인터의 주소를 함수로 넘기기 위해 필요 (int **p) |
포인터 배열 (문자열 목록 등) | char *argv[]는 char **argv 와 동일한 개념 |
2차원 배열의 동적 할당 | int **matrix 형태로 구현 가능 |
이중 구조를 다룰 때 | 포인터의 포인터가 필요한 경우 (예: 트리 구조, 링크드 리스트 노드 연결) |
📦 이중 포인터로 2차원 배열 만들기
int **matrix;
matrix = malloc(3 * sizeof(int *)); // 행 생성
for (int i = 0; i < 3; i++) {
matrix[i] = malloc(4 * sizeof(int)); // 각 행에 열 생성
}
matrix[1][2] = 99;
printf("matrix[1][2] = %d\n", matrix[1][2]);
이처럼 이중 포인터를 이용하면 유동적으로 크기를 조절 가능한 2차원 배열을 만들 수 있습니다.
📌 동적 할당을 했으면 free()도 반드시 해줘야 합니다.
✅ 요약 정리
개념 | 설명 |
*p | 일반 포인터, 값을 가리킴 |
**pp | 이중 포인터, 포인터를 가리킴 |
&p | 포인터 p의 주소 (이중 포인터 생성 시 필요) |
함수에 포인터 할당 | int **p를 전달하여 malloc 결과 반영 가능 |
2차원 배열 | int ** 구조로 구현 가능 |
728x90
'개발이야기 > C언어' 카테고리의 다른 글
[C언어] Malloc 파헤치기: 묵시적 할당기 (0) | 2025.07.02 |
---|---|
[C언어] malloc, free, calloc, realloc 완전 정리 - 힙 영역과 일반 배열의 차이까지 (0) | 2025.07.01 |
[C언어] 문자열과 포인터(char *str) 쉽게 이해하기 (1) | 2025.07.01 |
[C언어] 포인터(pointer) 이해하기: 주소연산자부터 배열까지 (0) | 2025.07.01 |
[C언어 알고리즘] 레드-블랙 트리 삭제, Extra Black 이해부터 Case별 복구까지 (0) | 2025.06.22 |