2022. 6. 13. 00:35ㆍ♣ C++
이번 포스팅에선 C++의 포인터에 대해 알아보도록 하겠습니다.
포인터 : 다른 변수, 혹은 그 변수의 메모리 공간 주소를 가리키는 변수
즉, 특정 변수가 저장되어 있는 메모리 주소
개발 환경 : VSCode, Windows 10
기본 개발 세팅은 다음과 같습니다.
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
// pointer
int num1 = 10;
int num2 = 4;
cout << "pointer 예시 \n";
return 0;
}
포인터 (Pointer)
포인터란? 메모리의 주소 값을 저장하는 변수입니다.
char형 변수가 문자를 저장하고, int형 변수가 정수를 저장하듯이, pointer는 주소를 저장합니다.
TCP School에서 가져왔습니다.
[포인터 선언]
타입 *포인터 이름 = &변수이름;
or
타입 *포인터 이름 = 주소값;
포인터는 위와 같은 방식으로 선언됩니다.
밑은 예제입니다.
int main()
{
int num1 = 5;
int *ptr_1 = &num1;
cout << "num1 의 주소는 "<< ptr_1 << " 입니다.";
}
결과
num1 의 주소는 0x61ff08 입니다.
[포인터 연산자]
포인터를 선언하고 활용함에 있어, 2개의 주요 연산자가 존재합니다.
1. 주소 연산자(&) : 변수의 이름 앞에 사용하여, 해당 변수의 주소 값을 반환합니다.
int *ptr_1 = &num1;
2. 참조 연산자(*) : 포인터 이름, 주소 앞에 사용하며 포인터가 가리키는 주소에 저장된 값을 반환합니다.
cout << "num1 의 주소에 저장된 값은 "<< *ptr_1 << " 입니다.";
num1 의 주소에 저장된 값은 5 입니다.
*포인터 이름을 사용한 결과, 주소에 저장된 값이 반환된 것을 확인할 수 있습니다.
기초적인 포인터 개념으로 코딩해보자!
int main()
{
double num1 = 3.14556456;
int num2 = 1234;
double *ptr_1 = &num1;
int *ptr_2 = &num2;
printf("num1 의 포인터 변수의 크기는 %d\n", sizeof(ptr_1));
cout << "num1 의 주소값은 " << ptr_1 << endl;
cout << "num1 의 값은 " << *ptr_1 << endl;
cout << "num2 의 주소값은 " << ptr_2 << endl;
cout << "num2 의 값은 " << *ptr_2 << endl;
}
결과
num1 의 포인터 변수의 크기는 4
num1 의 주소값은 0x61ff00
num1 의 값은 3.14556
num2 의 주소값은 0x61fefc
num2 의 값은 1234
쉽게 생각하면 됩니다. 포인터는 변수의 주소값을 가진 변수입니다.
[*포인터]는 주소값에 저장된 변수를, [포인터]는 주소값을 반환합니다.
포인터 연산
그저 주소를 가리키는 변수인데, 웬 연산?이라는 생각이 들 수 있습니다.
포인터는 그저 주소를 가리키기 위해 존재하는 것이 아닙니다. 나중에 배울 '메모리 동적 할당'을 위해 쓰입니다. 메모리를 원하는 주소에 할당하고, 해제하는 작업을 후에 하게 될 것입니다. 그때 원활하게 주소를 다루려면 당연히 관련 연산 작업도 이해해야 할 것입니다.
포인터 연산은 그 시작점입니다.
포인터 연산의 특징은 다음과 같습니다.
1) 포인터는 값을 증거/감소시키는 등의 제한된 연산만 가능합니다.
2) 포인터끼리의 연산(덧셈, 곱셈, 나눗셈)은 아무 의미가 없습니다.
3) 포인터끼리의 뺄셈은 두 포인터 사이의 거리를 의미합니다.
4) 포인터에 정수는 더하고 뺄 수 있지만, 실수는 허용되지 않습니다.
5) 포인터끼리 대입하거나 비교할 수 있습니다.
[타입별 포인터 연산]
포인터는 타입마다 연산에 따른 변화가 다릅니다.
만약 int형 타입의 포인터에 대하여, 1을 더하면 int형 메모리 크기(4)만큼 이동합니다.
int main()
{
int num2 = 1234;
int *ptr_2 = &num2;
int *ptr_3;
cout << ptr_2;
cout << "\n";
ptr_3 = ptr_2 + 1;
cout << ptr_3;
}
결과
0x61ff04
0x61ff08
ptr_2에 1을 더한 결과, 0x61ff04 -> 0x61ff08로 변한 것을 확인할 수 있습니다. int형 메모리 크기만큼 움직인 것에 주목해야 합니다. 실수형은 어떨까요?
int main()
{
double num2 = 1.234;
double *ptr_2 = &num2;
double *ptr_3;
cout << ptr_2;
cout << "\n";
ptr_3 = ptr_2 + 1;
cout << ptr_3;
}
결과
0x61ff00
0x61ff08
예상대로 실수형 메모리 크기인 8만큼 이동했음을 확인할 수 있습니다.
이렇듯이 포인터는 연산한다고 다 똑같은 결과가 나오는 것이 아닙니다. 타입마다 메모리 크기가 다르기에, 연산 결과도 모두 다름을 인지해야 합니다.
[포인터와 배열]
이 둘은 언뜻 봐서는 연관이 없어 보입니다. 하지만 미묘한 관계성이 있습니다.
어떤 부분에선 서로를 대체할 수도 있습니다. 배열의 이름을 포인터처럼 사용할 수 있으며, 포인터를 배열의 이름으로 사용할 수도 있습니다.
C++에서는 배열의 이름이 주소로 해석됩니다. 해당 배열의 첫 요소의 주소와 같습니다.
즉, array의 주소 값 = array의 첫번째 요소인 1의 주소값
int main()
{
int array[] = {1,2,3,4,5};
int *ptr_1 = array;
// array[i] 로도 가능하지만, 여기선 포인터도 배열처럼 쓰일 수 있음을 보여주고자 한다.
for (int i=0; i < 5; i++){
cout << i << " 번째 요소의 값은 " << ptr_1[i] << " 입니다.\n";
}
}
결과
0 번째 요소의 값은 1 입니다.
1 번째 요소의 값은 2 입니다.
2 번째 요소의 값은 3 입니다.
3 번째 요소의 값은 4 입니다.
4 번째 요소의 값은 5 입니다.
포인터를 배열에 대입한 결과, 포인터도 배열과 유사하게 기능함을 볼 수 있습니다. arr[i]를 통해, 배열에서 직접 값을 불러왔어도 똑같은 결과가 나왔을 것입니다.
다만, 배열과 포인터의 크기 계산에선 차이점을 보입니다.
int main()
{
int array[] = {1,2,3,4,5};
int *ptr_1 = array;
cout << sizeof(array) << endl;
cout << sizeof(ptr_1);
}
결과
20
4
배열을 sizeof() 했을 때는 배열의 크기를 반환했습니다. 하지만 포인터를 sizeof() 했을 때는 포인터 변수 자체의 크기를 출력했습니다.
[배열의 포인터 연산]
array[n] = *(array + n)
다음은 배열의 이름을 포인터처럼 사용하는 예제입니다.
포인터 연산을 통해 배열의 요소에 접근합니다.
int main()
{
int array[] = {1,2,3,4,5};
// 배열의 이름으로 포인터 연산을 통해 배열 요소에 접근
for (int i=0; i<5; i++){
cout << i+1 << " 번째 배열 요소의 주소값은 " << *(array + i) << " 입니다." << endl;
}
}
결과
1 번째 배열 요소의 주소값은 1 입니다.
2 번째 배열 요소의 주소값은 2 입니다.
3 번째 배열 요소의 주소값은 3 입니다.
4 번째 배열 요소의 주소값은 4 입니다.
5 번째 배열 요소의 주소값은 5 입니다.
처음 포인터에 대입한 배열의 주소 값은 배열의 첫 번째 주소와 같았습니다.
그 배열에 포인터 연산처럼 +2를 해줌으로써 배열의 3번째 요소를 나타낸 것이라 할 수 있습니다.
지금까지 포인터 개념과 연산하는 방법을 살펴보았습니다.
다음 포스팅에선 포인터의 존재 이유, 바로 메모리 동적 할당에 대해 다뤄보도록 하겠습니다.
'♣ C++' 카테고리의 다른 글
[C++] string 클래스와 메소드 (0) | 2022.06.16 |
---|---|
[C++] 메모리 동적 할당이 뭐에요? (0) | 2022.06.15 |
[C++] 1차원 배열, 다차원 배열 (0) | 2022.06.11 |
[C++] 조건문과 반복문을 활용해봅시다. (0) | 2022.06.10 |
[C++] 비트 연산자, 쉼표 연산자, 삼항 연산자, sizeof 연산자 (0) | 2022.06.09 |