포인터는 메모리의 주소를 담을 수 있는 타입이다.
일반적인 int, float 등은 '값'을 담지만 포인터는 기존 타입에 *을 추가로 붙여 그 타입의 '주소'를 담을 수 있는 타입이다.
예시로 int* a; 이면 int 타입의 변수의 주소를 담을 수 있는 포인터인 것이다.
하지만 난 의문이 들었다.
어차피 주소인데 왜 값에 해당하는 타입 필요하지?
맞다.
실제로 타입은 '주솟값'만 들어가는 데에는 아무런 문제가 없다.
실제로 void*라는 타입으로 변경해 타입은 모르지만 주솟값만 담을 수도 있다.
하지만 이렇게 void*로 담을 시
원래 포인터를 사용하는 방법 중, ++나 --로 주소값을 움직일 수 있는데 이 방식이나, []로 배열에 접근하는 방식 또한 사용할 수 없게 된다.
그 이유는 포인터를 이용해 주소를 이동할 때 포인터 앞에 값에 해당하는 타입의 바이트만큼 움직이기 때문이다.

예를 들어
int가 4바이트라 가정하고 1바이트당 0x100씩 움직인다고 가정했을 때
int* a = 0x100; 을
a++; 해주면
a == 0x500; 이라는 거다.만약
byte* a = 0x100; 을
a++; 하면
a == 0x200; 이 된다.
이 주소를 담는 것이 C++의 매우 핵심인 시스템인 것과 동시에 매우 위험한 시스템이다.
보통은 new 예약어를 사용해 Heap에 값을 만들어 주솟값을 반환받아 사용한다
ex) int* a = new int;
이 포인터의 값에 접근하기 위해서는 *을 사용하면 된다.
ex) *a == 3
Heap에 값을 생성하게 되는 new와 달리 Stack에 생성되는 변수의 주솟값 역시 담을 수 있는데,
&를 사용해 해당 변수의 주솟값을 얻어올 수 있다.
ex) int* b = &a;단, Stack에 생성되는 변수는 생명주기가 끝날 경우 자동으로 변수가 해제되므로 해제된 후 접근하지 않도록 매우 주의해야 한다.
new를 사용해 주솟값을 얻어왔을 때에도 delete 예약어를 이용해 해제하지 않는다면 메모리가 해제되지 않으므로 매우 주의해야 한다.
ex) delete a;