이중 포인터는 대상 값이 아니라 포인터 변수 자체를 바꿔야 할 때 필요합니다.
- 함수 안에서
malloc한 결과를 호출자 포인터에 돌려줘야 한다 char **argv같은 선언이 왜 나오는지 다시 헷갈린다*pp와**pp중 어느 쪽이 포인터를 바꾸고, 어느 쪽이 값을 바꾸는지 구분이 안 된다
숏컷 코드
c
int *data = NULL;
good_alloc(&data);T *는 원본 값을 바꾸는 데 쓰고, T **는 호출자의 포인터 변수 자체를 다른 주소로 돌릴 때 씁니다.
문법
c
int value = 10;
int *p = &value;
int pp = &p;
printf("%d\n", value);
printf("%p\n", (void *)p);
printf("%p\n", (void *)pp);
printf("%d\n", pp);가장 흔한 케이스는 할당 결과를 호출자 포인터에 돌려주는 패턴입니다.
c
void wrong_alloc(int *p) {
p = malloc(4 * sizeof(int)); // 호출자 포인터는 안 바뀜
}
void good_alloc(int **out) {
*out = malloc(4 * sizeof(int)); // 호출자 포인터를 갱신
}
int *data = NULL;
good_alloc(&data);즉 이중 포인터는 out parameter처럼 읽는 편이 자연스럽습니다.
읽는 법
c
int value = 7;
int *p = &value;
int pp = &p;
*pp = NULL; // p 자체를 바꿈
p = &value;
pp = 99; // value를 바꿈*pp = ...는 호출자 포인터를 다른 곳으로 돌립니다.**pp = ...는 그 포인터가 가리키는 원본 값을 바꿉니다.
argv가 char **인 것도 같은 원리입니다. 문자열 포인터들의 목록을 가리키는 포인터이기 때문입니다.
c
int main(int argc, char **argv) {
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
}체크포인트
- 포인터 안의 값을 바꾸면
T * - 포인터 변수 자체를 바꾸면
T ** *pp는 포인터 한 단계**pp는 원본 값argv처럼 포인터 목록을 다루는 구조에서도 자연스럽게 나옵니다
주의할 점
malloc 결과를 *out에 바로 넣는 패턴은 실패 시 기존 포인터를 잃기 쉽습니다. 기존 메모리를 유지해야 하는 상황이면 임시 포인터에 먼저 저장한 뒤 성공했을 때만 *out에 대입하세요.
참고 링크
1 sources