매우 기초적인 설명이지만 포인터에서 중요한 개념이기에 다시 짚어볼 필요가 있다.
void Test(int a)
{
a = 100;
}
void main()
{
int a = 10;
Test(a);
}
위와 같은 경우 실제 a의 값은 변하지 않는다.
main에서의 a와 Test에서의 a는 각 지역의 지역변수로 할당되기 때문, Test()는 main의 a 값을 복사해서 가져온 것일 뿐 전혀 다른 메모리 공간에 할당된다.
그럼 포인터 혹은 참조자(&)를 사용한다면?
void Test(int* a)
{
*a = 100;
}
void main()
{
int a = 10;
Test(&a);
}
이 때는 실제 a의 값은 100이 된다.
Test()에서는 인자로 받아올 매개변수의 포인터 타입을 요구한다. 즉, main에서의 a의 실제 값이 저장되어있는 메모리 공간의 주소를 받아와서 수정한 것이기에 실제 a의 값 또한 수정된다.
그렇다면 이중 포인터는 무엇일까?
이중 포인터라고 해서 일반 포인터와 다르지 않다.
일반 포인터와 일맥상통하는 개념이다.
이 것만 알면된다.
이중 포인터는 포인터의 변수의 주소값을 저장하는 포인터 변수이다.
자세하게 풀어서 설명해보자.
포인터는 특정 객체의 주소 값을 저장하는 변수이다.
그렇다면 객체의 주소를 저장하는 변수 또한 하나의 객체로서 특정 메모리 공간을 할당 받을 것이고,
해당 메모리 공간을 해당 객체의 주소로 채울 것이다.
그렇다면, 포인터 변수 또한 자신이 메모리에 어느 공간에 할당되었는지 주소가 있을 것이다.
그 주소 값을 확인하는 것이 이중 포인터이다.
예시를 보며 알아보자
void Test(int* *a)
{
③ *a = new int;
④ **a = 10;
}
void main()
{
① int* a = nullptr;
② Test(&a);
}
Test()는 이중 포인터 타입의 매개변수를 요구한다.
쉽게 설명하면 포인터 타입 변수의 주소 값을 요구하는 것이다.
위의 예시를 자세하게 설명하면,
① int 포인터 타입 변수 a는 nullptr이다.
포인터 변수 a는 메모리 공간을 할당 받았지만 아직 아무 정보도 저장하지 않고있다.
② Test() 함수에 포인터 변수인 main()의 a의 주소 값을 넘긴다.
포인터 변수인 a 안에 담긴 정보가 아닌 실제 메모리 주소 값을 넘긴다. a의 주소값을 포인터 타입으로 받아왔음으로 Test()에 들어온 실제 정보는 a의 주소인 것이다.
③ int 자료형을 동적할당하고, 매개변수로 받아온 a의 주소를 역참조하여 동적할당 된 곳의 주소를 저장한다.
이 때 *a 에서 *은 단항 간접 참조 연산자를 통해 a에 담긴 정보(a가 가리키는 주소)를 확인(혹은 수정) 할 수 있다.
즉, a를 역참조 한다 -> a에 담긴 정보를 확인(혹은 수정)한다. a의 주소가 아닌 a안에 들어있는 정보를(주소 값만 들어있는 것은 아니다.) 확인(혹은 수정)하는 것.④ 매개변수로 받아온 a에 저장된 실제 데이터를 수정한다.
③(*a)에서 확인한 것은 동적할당한 데이터의 주소 값을 나타내고, ④(**a)에서 확인 한 것은 동적할당한 데이터의 실제 메모리 공간(정보)이다.
이번엔 직접 코드로 출력값을 알아보자

main에서 return 값을 설정 안한 것은 넘어가자.

위에서 말한 것처럼 main()의 a와 Test()의 a는 전혀 다른 변수임을 알 수 있다.
매개변수로 main()의 a의 주소를 받아왔으니 당연한 얘기이다.main()의 a에는 동적할당한(new int) 곳의 메모리 주소 값이 담겨있다.
*a 는 Test()의 a에 담긴 주소로 접근(예시에서는 main()의 a로 접근)하여 해당 주소안에 저장된 값을 확인하는 것이다.
main()의 a에 동적할당된 곳 주소로 접근하면 동적할당한 int의 실제 값이 나온다.
**a 는 Test()의 a에 담긴 주소로 접근(예시에서는 main()의 a로 접근)하여 해당 주소안에 저장된 값을 확인하고, 확인한 주소로 접근해서 저장된 값을 확인(혹은 수정)하는 것이다.
그렇다면
포인터 변수 pA -> 포인터 변수 a의 주소를 가리키는 이중 포인터 변수 ppA -> 이중 포인터 변수 ppA를 가리키는 삼중 포인터 변수 pppA -> 삼중 포인터 변수 pppA를 가리키는 사중 포인터 변수 ppppA -> ... ... ...
이와 같이 이중 포인터 개념은 끝없이 확장될 수 있다.
하지만! 이중 포인터 이상은 사용하지 않는다.
사용할 필요가 없다고 하는게 맞는것 같다. 필자는 사용해본 적도 사용의 필요성을 느낀적도 없다.
C++로 코딩을 하다보면 포인터를 사용하는 상황이 아주 많이 생긴다. 그렇기에 포인터를 수정하고 싶은 경우도 생기기 마련이다. 그럴 때 사용하는 것이 이중 포인터이다.
이중 포인터를 처음 접했을 때는 굉장히 햇갈렸지만, 포인터 개념을 이해하고 포인터 관점에서 이중 포인터를 바라보니 "사실 이중 포인터도 결국 포인터다." 라는 것을 깨달았다.
머리속에서 생각한 내용을 코드로 표현하고 값을 출력하고, 확인해 보며 포인터를 직접 체감하는 것이 중요하다.
추가로
역참조 연산과 포인터, 참조자를 함께 생각하면 햇갈리지만 각각의 개념을 제대로 이해하면 생각하기 편할 것이다.
글 잘 봤습니다.