단어 그대로, 포인터의 포인터다. 즉, (어떤 값에 대한 주소를 저장하는 포인터)의 주소를 저장하는 포인터다.
#include <stdio.h>
int main()
{
int *numPtr1; // 단일 포인터 선언
int **numPtr2; // 이중 포인터 선언
int num1 = 10;
numPtr1 = &num1; // num1의 메모리 주소 저장
numPtr2 = &numPtr1; // numPtr1의 메모리 주소 저장
printf("%d\n", **numPtr2); // 10: 포인터를 두 번 역참조하여 num1의 메모리 주소에 접근
}
포인터도 실제로는 변수이기 때문에 메모리 주소를 구할 수 있다. 하지만 포인터의 메모리 주소는 일반 포인터에 저장할 수 없고, '**numPtr2'처럼 이중 포인터에 저장해야 한다.(컴파일 에러)
'int **numPtr2' 를 영어로 읽으면 pointer to pointer to int가 된다.(numPtr2 → numPtr1 → num1).
당연히 이중 포인터로 연결된 값을 가져올 때도, 역참조 연산자인 '*'를 2회 활용하면 된다.
포인터와 이중 포인터의 연산은 아래와 같다.
char는 1byte 자료형이므로 포인터(pt1)에 1을 더하면, 1이 늘어난다. 반면 char의 이중포인터(ptr2)에 1을 더하면, 포인터의 사이즈인 8만큼이 늘어난다.
또, int는 4byte 자료형이므로 포인터(pt3)에 1을 더하면 4가 늘어난다. 반면 int의 이중포인터(ptr4)에 1을 더하면, 포인터의 사이즈인 8만큼이 똑같이 늘어난다.
#include <stdio.h>
int main()
{
char x=2;
char* ptr1 = &x;
char** ptr2 = &ptr1;
printf("%p\n", ptr1); //0x7ffee4e7075f
printf("%p\n", ptr1+1); //0x7ffee4e70760
printf("%p\n", ptr2); //0x7ffee4e70750
printf("%p\n", ptr2+1); //0x7ffee4e70758
int n = 3;
int* ptr3 = &n;
int** ptr4 = &ptr3;
printf("%p\n", ptr3); //0x7ffee4e70744
printf("%p\n", ptr3+1); //0x7ffee4e70748
printf("%p\n", ptr4); //0x7ffee4e70738
printf("%p\n", ptr4+1); //0x7ffee4e70740
}