포인터 관련한 연산의 종류는 4가지가 있다.
주소 연산자
1. & 연산
- 주소 연산자도 이전 글에서 소개했듯이, 변수의 주소에 접근하고 싶을 때, 앞에 붙여서 사용한다.
int num = 1;
int* p= #
만약 num 이 0x12 의 주소를 가지고 있다면 &num 연산을 통해서 0x12 라는 값이 도출된다.
산술연산자
1. + (더하기)
- 첫번째로 더하기 연산이다. 포인터는 주소를 저장하는 변수 타입이다. 그리고 int형 포인터 변수는 int형 변수의 주소를 저장할 수 있다.
이 주소에 +1 을 한다고 하자.
int* p;
int num=2;
p=#
p++;
만약 이렇게 포인터 변수값을 1 증가시키면 결과적으로 4바이트 뒤에있는 주소를 가리키게 된다.
num변수가 0x12 라는 주소를 가지고 있다고 하자.
int 는 4바이트이기 때문에 0x12~0x15 까지를 차지한다. 때문에 p++을 통한 p의 값은 0x16이 된다.
즉 int 의 크기만큼을 증가시킨 것이다.
따라서, char 형 포인터변수를 1 증가시키면 1바이트 증가한 주소값이 들어있을 것이고 double형 포인터 변수를 1 증가시키면 8바이트 증가한 주소 값이 들어있을 것이다.
2. - (빼기)
- 빼기 연산도 더하기와 비슷하다.
다른점은 int형 포인터 변수에서 1을 빼면 0x12 에서 0x0D가 된다.
또 char형 포인터 변수에서 1을 빼면 0x12 에서 0x11이 되는 것이다.
간접연산자
1. *
- * 연산은 이전 글에서도 소개했듯이, 포인터 변수앞에 붙여서 가리키고 있는 주소의 바구니에 있는 값에 접근하겠다는 뜻이다. 따라서
int* p = #
*p = 1
int num2 = *p;
위 처럼 *p 즉 p가 저장하고 있는 주소로 가서 그 바구니에 1을 대입하라는 의미이다.
또 num2에 p가 저장하고 있는 주소의 값을 대입한다는 뜻이다.
배울 때, 헷갈렸던 코드가 있다.
*p++
(*p)++
위의 두 코드인데, 첫번재 코드는 연산자의 우선순위 상 p주소에서 더하기 연산 후 그 주소의 바구니에 접근하겠다는 뜻이다.
두번째 코드는 p가 가리키는 주소에 있는 값에 접근해서 그 값을 1 증가시킨다는 의미이다.
즉, 첫번째는 주소를 두번째는 주소에 있는 값을 1 증가시키는 연산이다.
간접 멤버 연산자
1. -> 연산
- 구조체나 클래스와 연관이 있는 연산이다.
먼저 간접연산자를 통한 구조체 멤버변수에 접근하는 코드이다.
struct Player
{
int hp;
int damage;
};
Player player;
player.hp = 100;
player.damage = 20;
Player* p1 = &player;
(*p1).hp = 90;
(*p1).damage = 10;
Player 타입의 포인터 변수 p1은 player변수의 주소를 가지고 있다.
p1을 통해서 player변수의 멤버변수의 값을 변경하고 싶을 때, 우선 * 연산으로 player에 접근한 후, '.' 연산자를 통해 멤버변수에 접근하게 된다.
즉 * 연산 후 . 연산을 실행한다.
간접멤버연산자는 이를 한번에 해결해준다.
p1->hp = 80;
이런식으로 좀 더 간단하게 사용할 수 있다.
지금까지 포인터와 관련된 4가지 연산을 소개했다.
참고로 구조체변수가 메모리에 저장될 때는, player로 예를 들면, hp가 0x12에 저장되면 damage는 0x16에 저장된다.
따라서 p1은 0x12를 갖고있으며 p1-> (간접멤버연산자 혹은 * 연산자)를 통해 멤버변수에 접근하면 시작주소인 0x12에서부터 각 멤버변수의 오프셋만큼 더한 주소에 접근하게 되는 것이다.
p1->damage 에서 damage의 오프셋은 1이며 시작주소인 0x12 부터 1* 4바이트만큼의 주소가 더해져 0x16에 접근하게 된다.
'C++' 카테고리의 다른 글
Visual Studio - LNK2001 에러 (0) | 2023.09.02 |
---|---|
포인터(Pointer) 기초 - C++ (0) | 2023.07.29 |