이 문서의 내용
포인터란?
변수(Variables)는 어떤 데이터를 저장하기 위해 메모리에 공간을 할당 받습니다. 이때 메모리의 시작 주소를 주소 값이라고 부릅니다.
예를 들어 다음과 같이 int a 변수를 선언하면 4바이트 메모리 공간을 할당 받고 이때 주소 값은 0x0001입니다.
마찬가지로 short b 변수는 2바이트를 사용하며 주소 값은 0x0006입니다.
이를 코드에서 확인하려면 다음과 같이 작성합니다.
int a = 1234567;
std::cout << &a;
프로그램을 실행하면 다음과 같이 출력됩니다.
0x61ff0c
이때 &a는 변수 a에 대한 주소를 의미하며 &를 주소 연산자라고 부릅니다.
포인터(Pointer)는 이처럼 변수에 할당되어 있는 메모리 주소 값을 저장하는 변수입니다.
포인터 또한 하나의 변수이며 다음과 같이 선언 할 수 있습니다.
[참조 변수 타입]* [변수이름] = &[참조 변수 이름]
예를 들어 예시의 변수 int a의 주소 값을 저장하는 포인터 변수 ap는 다음과 같습니다.
int a = 1234567;
int* ap = &a;
std::cout << &a << std::endl;
std::cout << ap << std::endl;
포인터 변수에는 참조 변수의 주소 값이 저장되어 있으므로, 예시의 출력 결과는 동일한 주소 값을 표시합니다.
0x61ff0c
0x61ff0c
주소 연산자(&)
앞서 소개한 주소 연산자 &는 어떤 변수에 할당된 메모리 주소를 확인하기 위해서 사용합니다.
포인터 변수에는 참조하는 변수의 주소 값이 저장되어야 하므로, 포인터 변수에 다른 변수를 할당하는 구문에서는 & 연산자가 사용됩니다.
int a = 1234567;
int* ap = &a;
역참조 연산자(*)
메모리 주소 값을 알고있으면 해당 메모리에 저장된 값을 읽을 수 있습니다.
이때 사용되는 키워드가 역참조 연산자 *입니다.
int a = 1234567;
std::cout << a << std::endl;
std::cout << *&a << std::endl;
& 연산자가 포인터에 다른 변수의 주소 값을 저장하기 위해 사용된다면 * 연산자는 포인터가 가리키는 주소 값에 실제 저장된 값에 접근하기 위해 사용됩니다.
int a = 1234567;
int* ap = &a;
// output: 1234567
std::cout << *ap << std::endl;
포인터 사용 예시
포인터에서 가장 중요한 키워드는 포인터 변수가 가리키는 메모리 주소의 값을 * 연산자로 접근 가능하다는 점입니다.
그리고 메모리 주소 값은 특정 포인터와 1:1로 매핑되는 것은 아닙니다.
int a = 1000;
int* ap0 = &a;
int* ap1 = &a;
// handle origin variable
a = 2000;
std::cout << a << " " << *ap0 << " " << *ap1 << std::endl;
// handle pointer 0
*ap0 = 3000;
std::cout << a << " " << *ap0 << " " << *ap1 << std::endl;
// handle pointer 1
*ap1 = 4000;
std::cout << a << " " << *ap0 << " " << *ap1 << std::endl;
예시에서 변수 int a의 주소 값을 저장하는 두 개의 포인터 변수 ap0 ap1을 다루고 있습니다.
프로그램을 실행하면 3개의 변수에서 실제 저장하는 값이 일치합니다.
2000 2000 2000
3000 3000 3000
4000 4000 4000
서로 다른 변수가 동일한 메모리 주소에 접근하기 때문에 가능한 일입니다.
포인터는 예시처럼 여러 개의 포인터 변수를 사용하여 하나의 메모리 주소를 다루기 위해 사용됩니다.
주소의 증감 연산
포인터 변수에는 주소 값이 저장되어 있으며 주소 값은 증감 연산자로 다른 주소를 가리키는 것이 가능합니다.
int arr[] = { 1, 2, 3, 4 };
int* ap = &arr[0];
std::cout << *ap << std::endl;
std::cout << *(ap + 1) << std::endl;
std::cout << *(ap + 2) << std::endl;
std::cout << *(ap + 3) << std::endl;
코드 | 비고 | |
배열의 |
||
배열의 |
||
포인터가 가리키는 메모리 주소 값을 증가시켜 배열의 |
||
포인터가 가리키는 메모리 주소 값을 증가시켜 배열의 |
||
포인터가 가리키는 메모리 주소 값을 증가시켜 배열의 |
포인터 변수의 선언자에는 가리키는 메모리 주소 값에 저장된 실제 데이터 타입이 포함됩니다.
이는 포인터 변수가 저장하고 있는 주소 값에 증감 연산을 할 때 주소 값을 얼만큼 증감 시켜야하는지에 대한 힌트입니다.
다음 예시를 통해 주소의 증감 연산 결과를 확인합니다.
short a = 10;
int b = 20;
short* ap = &a;
int* bp = &b;
std::cout << ap << std::endl;
std::cout << ap + 1 << std::endl;
std::cout << ap + 2 << std::endl;
std::cout << std::endl;
std::cout << bp << std::endl;
std::cout << bp + 1 << std::endl;
std::cout << bp + 2 << std::endl;
코드 | 비고 | |
따라서 각 증감 연산자에 의한 주소는 |
||
따라서 각 증감 연산자에 의한 주소는 |
||
프로그램을 실행하고 출력 결과를 확인합니다. 각 데이터 타입이 사용하는 메모리 크기만큼 주소가 이동하는 것을 알 수 있습니다.
0x61ff06
0x61ff08
0x61ff0a
0x61ff00
0x61ff04
0x61ff08
정리 및 복습
변수(Variables)는 어떤 데이터를 저장하기 위한 목적으로 사용합니다. 이를 위해 메모리 공간을 할당합니다.- 변수가 데이터 저장을 위해 할당된
메모리 공간의 시작 지점은 주소 값이라고 부릅니다. 포인터(Pointer)는 주소 값을 저장 할 수 있는 변수입니다.- 포인터에 주소 값을 저장할 때는 가리키려는 변수에 대해서 주소 연산자
&를 사용합니다. - 포인터에 가리키는 주소 값에 대한 실제 데이터에 접근하려면 역참조 연산자
*를 사용합니다. - 포인터가 가리키는 주소 값은 증감 연산자
+-로 주소 값을 이동시킬 수 있습니다. - 주소 값은 포인터가 가리키는
실제 데이터 타입이 사용하는 메모리 크기만큼 이동합니다.
'C++ > C, C++, STL' 카테고리의 다른 글
자기 자신을 나타내는 this 포인터 (0) | 2024.02.04 |
---|---|
얕은 복사(Shallow copy)와 깊은 복사(Deep copy) (0) | 2024.02.04 |
이중 포인터와 동적 다차원 배열에 대한 이해 (0) | 2024.02.04 |
표준 입출력을 위한 std::cout, std::cin (0) | 2024.02.03 |
네임스페이스(Namespace)란? (0) | 2024.02.03 |