Category (Click)
개발보드 덕질하기
🏢

[포인터] 변수는 어디에 저장될까?

주소 연산자 &foo;

위 코드와 같이 변수를 생성한 후 변수 앞에 &기호를 붙여주면 변수의 주소값을 알아낼 수 있습니다. 여기서 & 기호는 주소연산자라고 부르며, printf() 함수에서 주소값을 출력하기 위해 형식 지정자로 %p를 사용합니다. 메모리 주소는 16진수를 사용하기 때문에 출력된 결과를 확인해보면 0x…으로 시작하는 16진수 값을 확인할 수 있습니다.

범용 포인터 변수 void *foo;

그렇다면 이제 이 포인터를 어딘가에 저장해보아야겠죠? 포인터를 저장히기 위해서는 포인터 변수를 생성해야 합니다. 그러기 위해서는 포인터를 저장할 수 있는 변수를 생성해야 하는데요, 변수의 타입은 void로, 변수 이름 앞에는 별표 또는 Asterisk라고 부르는 * 문자를 붙여주어야 합니다.
요즈음 출시되는 대부분의 컴퓨터는 64bit 운영체제를 사용합니다. 여기서 64bit라는 수치는 메모리의 주소가 64bit 변수로 표현된다는 뜻이며, 메모리를 최대한으로 구성했을 때 8bit짜리 메모리 블럭이 2의 64승만큼 존재한다는 뜻입니다. 따라서 포인터 역시 0부터 2의 64승까지의 데이터를 저장할 수 있어야 하는데요, 이때문에 64bit 운영체제에서의 모든 포인터는 64bit(8byte)의 공간을 차지합니다.
말이 어려워서 포인터이지 변수의 주소값을 저장하는 unsigned long long 형 변수(uint64_t)라 생각하면 편합니다.
또한 포인터 역시 변수이기 때문에 포인터 변수의 주소값을 얻을 수도 있습니다.
이러한 포인터의 포인터를 변수에 저장하기 위해서는 *를 2번 붙여 변수를 생성하면 됩니다.
포인터 변수는 그렇다 쳐도 포인터 변수의 포인터는 도대체 어디다가 쓰는지 궁금할 수도 있는데요, 뒤에서 설명할 포인터의 용도에 대해 알게 된다면 자연스럽게 이해가 될겁니다.

역참조 연산자 *

C언어의 여러 기호들은 사용하는 위치에 따라 서로 다른 의미를 가질 수 있습니다. 여기서의 * 기호가 이에 해당합니다.
포인터 변수에 저장된 주소값에서 데이터를 가져올 때에는 역참조 연산자인 *를 사용합니다. 이때 메모리에 저장된 데이터 만으로는 데이터의 형식(int, char 등..)을 알 수 없기 때문에 메모리에 저장된 데이터가 어떤 형식인지 미리 알려주어야 합니다.
위 코드의 6번줄에 주목해보면 역참조 연산자 *와 포인터 변수 foo_p 사이에 형 변환 연산자인 (int *)가 있습니다. 연산자 우선순위에 따라 foo_p의 자료형이 int *라는 타입으로 우선 변환되고, 그 뒤에 역참조 연산이 수행되어 data에 값이 저장됩니다.
여기서 형 변환 연산자 (int *)는 포인터가 가르키고 있는 메모리 주소가 int 타입이라는 것을 의미합니다.

타입 지정 포인터 int * char * unsigned int * long * unsigned long long *

앞서 포인터 변수를 이용해 데이터를 가지고오기 위해서는 형 변환 연산자를 이용해 메모리에 있는 데이터가 어느 형태인지 알려주어야 한다고 했습니다. 메모리의 주소값을 저장하는 포인터 변수에 변수의 타입에 대한 정보가 없어서 그런데요, 타입 지정 포인터를 사용하면 번거로운 형변환 과정 없이 역참조를 수행할 수 있습니다.
위 코드의 2번 줄과 같이 포인터 변수를 생성할 때 void가 아닌 포인터 변수에서 저장할 변수 데이터의 타입(int)을 입력하면 생성되는 포인터 변수는 오직 하나의 데이터 타입의 포인터만을 저장할 수 있습니다.
물론 이런 방식으로 생성되는 포인터 변수 역시 메모리 주소는 PC의 bit수가 변하지 않는 한 고정되기 때문에 64 bit(8 byte)의 저장 공간을 차지합니다.