이중 포인터(Double pointer)란?
이중 포인터는 포인터에 대한 포인터(Pointer to Pointers)입니다.
포인터가 변수(Variables)의 주소 값을 저장한다면 이중 포인터는 포인터의 주소 값을 저장합니다.
int a = 10;
int* ap = &a;
int** app = ≈
std::cout << a << std::endl;
std::cout << *ap << std::endl;
std::cout << **app << std::endl;
코드 | 비고 | |
변수 |
||
변수 |
||
출력되는 값은 모두 변수 |
||
앞서 소개한 것처럼 포인터가 변수의 주소 값을 저장합니다.
마찬가지로 포인터 역시 변수이기 때문에 메모리로부터 주소 값을 할당 받습니다.
이중 포인터는 이 주소를 가리킵니다.
이중 포인터 또한 변수이기 때문에 주소 값을 갖습니다.
이중 포인터의 주소 값을 저장하는 포인터 변수를 만들면 이를 삼중 포인터라고 부릅니다. 하지만 사람이 이해하기 어려운 다차원 구조인데다가 보통은 이중 포인터로 충분해 사용되지는 않습니다.
배열과 포인터
C++에서 정적 배열을 선언하는 구문은 다음과 같습니다.
int arr[] = { 1, 2, 3 };
배열 또한 변수이기 때문에 주소 값을 갖습니다. 따라서 배열을 포인터로 가리킬 수 있습니다.
이때는 정적 배열 선언 구문 대신 new 키워드로 동적 배열 선언을 사용해야합니다.
int* arr = new int[3] { 1, 2, 3 };
4바이트 크기의 int 타입을 가리키는 포인터에 + - 증감 연산을 하면 주소 값을 4씩 이동합니다(이 블로그의 문서: 포인터(Pointer)와 주소 연산자(&), 역참조 연산자(*) 그리고 주소의 증감 연산 처리 참고).
int* arr = new int[3] { 1, 2, 3 };
std::cout << "address is " << (arr + 0) << " and value is " << *(arr + 0) << std::endl;
std::cout << "address is " << (arr + 1) << " and value is " << *(arr + 1) << std::endl;
std::cout << "address is " << (arr + 2) << " and value is " << *(arr + 2) << std::endl;
프로그램을 실행하면 주소가 int 타입의 크기만큼 이동하는 것을 알 수 있습니다.
address is 0x7b6f10 and value is 1
address is 0x7b6f14 and value is 2
address is 0x7b6f18 and value is 3
이중 배열과 이중 포인터
배열을 포인터로 가리키는 것처럼 이중 배열도 이중 포인터로 가리킬 수 있습니다.
마찬가지로 new 키워드로 동적 배열 선언을합니다.
int** arr = new int[2][3] { { 1, 2, 3 }, { 4, 5, 6 }};
하지만 위와 같은 예시 코드는 컴파일 오류를 발생시킵니다.
a value of type "int (*)[3]" cannot be used to initialize an entity of type "int **"C/C++(144)
이중 배열에 대한 포인터는 다음과 같이 선언합니다.
int (*arr)[3] = new int[2][3] { { 1, 2, 3 }, { 4, 5, 6 }};
C++ 11 버전부터는 auto 키워드를 사용하여 단순화 할 수 있습니다.
auto arr = new int[2][3] { { 1, 2, 3 }, { 4, 5, 6 }};
이중 배열을 가리키는 이중 포인터의 사용은 좀 더 복잡합니다.
int (*arr)[3] = new int[2][3] { { 1, 2, 3 }, { 4, 5, 6 }};
std::cout << "address is " << (*(arr + 0) + 0) << "and value is " << *(*(arr + 0) + 0) << std::endl;
std::cout << "address is " << (*(arr + 0) + 1) << "and value is " << *(*(arr + 0) + 1) << std::endl;
std::cout << "address is " << (*(arr + 0) + 2) << "and value is " << *(*(arr + 0) + 2) << std::endl;
std::cout << std::endl;
std::cout << "address is " << (*(arr + 1) + 0) << "and value is " << *(*(arr + 1) + 0) << std::endl;
std::cout << "address is " << (*(arr + 1) + 1) << "and value is " << *(*(arr + 1) + 1) << std::endl;
std::cout << "address is " << (*(arr + 1) + 2) << "and value is " << *(*(arr + 1) + 2) << std::endl;
코드 | 비고 | |
마지막으로 이 주소의 값을 |
||
마지막으로 이 주소의 값을 |
||
마지막으로 이 주소의 값을 |
정리 및 복습
변수(Variables)는 메모리에 할당된 주소 값을 갖습니다.포인터(Pointer)는 변수가 사용하는 주소 값을 가리키는 변수입니다.- 포인터 역시 변수이기 때문에 주소 값을 갖습니다.
이중 포인터는 포인터의 주소 값을 가리키는 변수입니다. 동적 배열은 포인터로 가리킬 수 있습니다.
int* arr = new int[3] { 1, 2, 3 };
동적 이중 배열은 이중 포인터로 가리킬 수 있습니다.C++ 11버전부터는auto키워드를 사용 할 수 있습니다.
int (*arr)[3] = new int[2][3] { { 1, 2, 3 }, { 4, 5, 6 }};
'C++ > C, C++, STL' 카테고리의 다른 글
자기 자신을 나타내는 this 포인터 (0) | 2024.02.04 |
---|---|
얕은 복사(Shallow copy)와 깊은 복사(Deep copy) (0) | 2024.02.04 |
포인터(Pointer)와 주소 연산자(&), 역참조 연산자(*) 그리고 주소의 증감 연산 처리 (0) | 2024.02.04 |
표준 입출력을 위한 std::cout, std::cin (0) | 2024.02.03 |
네임스페이스(Namespace)란? (0) | 2024.02.03 |