메모리에 직접적인 접근을 가능하게 해주는 기능.
우리가 변수를 선언하면 이 변수는 메모리에 공간이 할당된다. 이때 메모리상에서 할당 받은 주소값을 저장하는 변수가 바로 포인터 변수이다.
포인터 변수 선언하기
결국은 주소값을 변수에 저장해야 하니 포인터값을 변수에 넣어야 한다. 선언 및 초기화 방법을 알아보자.
#include <stdio.h>
int main () {
int num = 10; // int형 변수
int * pnum; // int형 포인터 선언
pnum = # //num의 주소값으로 초기화, int * pnum = #로 한번에 초기화도 가능하다.
printf("num : %d, pnum = %p", num, pnum); // %p는 주소를 출력하기 위한 서식문자
}
원하는 타입의 포인터 변수를 선언하려면, type * var_name의 형식으로 선언하면 된다. 이때, 주소를 저장하고자 하는 변수의 타입과 일치해야 한다는 것을 명심하자.
이때 *연산자가 붙는데, 이는 변수를 선언할 때, 이 변수가 포인터임을 가르킨다.
또한, &연산자를 pnum에 대입한 것을 볼 수 있는데, & 연산자는 bit연산의 AND연산자로도 쓰이지만, 변수의 메모리 주소를 반환하는데 쓰이기도 한다.
출력해보면
과 같이 나옴을 알 수 있다. 메모리의 주소는 16진수로 나타내진다.
포인터와 관련된 연산자 - &, *
먼저 &연산자는 피연산자의 주소값을 반환한다.
*연산자는 포인터가 가르키는 메모리 공간에 접근할 때 사용하는 연산자이다.
#include <stdio.h>
int main () {
int num = 10;
int * pnum = #
printf("%d %d",num,*pnum);
return 0;
}
이 코드를 출력해보면 num과 *pnum이 같은 값임을 알 수 있다.
포인터의 형이 중요한 이유
앞서 포인터는 가르키는 변수의 형과 같은 형의 포인터로 선언해야 한다고 했다. 그 이유는 형(type)을 기준으로 메모리 공간을 읽어오기 때문이다. 다음 예제를 보자.
##include <stdio.h>
int main () {
double num = 10.12;
int * pnum = #
printf("%d",*pnum);
return 0;
}
출력해보면 전혀 엉뚱한 값이 나오게 된다.
num은 double형으로 8바이트를 차지하고 있다. 하지만 포인터인 pnum은 int형으로 4바이트를 읽는다.
이런식으로 포인터의 형은 메모리를 읽는 기준이 되기 때문에 포인터의 형을 맞추는 것은 중요하다. 하지만 C언어는 메모리접근의 유연성을 위해 컴파일에러를 발생시키지 않는다. (물론 경고메세지는 뜬다). 그렇기에 더더욱 중요하다.