포인터의 이해

Written on April 25, 2017

C언어에서 포인터는 메모리 주소이 주소로부터 시작하는 곳에 저장된 값의 자료형 정보를 가지고 있습니다.

실제로 포인터를 사용한 소스 코드는 다음과 같습니다.

#include <stdio.h>

int main(){
  int x=50;
  int* px=&x; // '&' : 변수의 주소 값을 반환하는 연산자
  
  printf("메모리 주소 : %p\n",px); // '%p'는 포인터 변수의 출력 형식
  printf("포인터가 가리키는 곳에 저장된 값 : %d\n",*px); // '*' : 포인터가 가리키는 메모리를 참조하는 연산자
  
  return 0;
}
출력 결과
메모리 주소 : 0x12ff73
포인터가 가리키는 곳에 저장된  : 50

(출력 결과에서 메모리 주소는 달라질 수 있습니다.)

여기서 px는 포인터형의 변수입니다. (int는 정수형, double은 실수형인 것 같이 새로운 자료형으로 이해하시면 될 것 같습니다.)

앞에서 설명한 것과 같이 포인터는 메모리 주소이 주소로부터 시작하는 곳에 저장된 값의 자료형 정보를 가지고 있습니다.

따라서 int* px=&x에서는 포인터형 변수 px정수형 변수 x의 주소(&x)를 대입하여 px를 초기화해주고 있습니다.

하나의 변수의 메모리 주소는 16진수(16진수에 대한 자세한 설명은 여기를 참고)의 연속된 값을 가지고 프로그램이 실행될 때 마다 변경되지만,

이번 글에서 정수형 변수 x는 0x12ff73~0x12ff76에 걸쳐 저장(int는 4바이트의 저장공간을 차지하기 때문)되어있고 이 값은 변하지 않는다고 가정하겠습니다.

int_x

x의 주소가 0x12ff73~0x12ff76의 값을 가진다면 printf("메모리 주소 : %p\n",px);의 출력값은 왜 0x12ff73 하나 뿐일까요?

이유는 포인터에는 이 주소로부터 시작하는 곳에 저장된 값의 자료형 정보가 저장되어 있기 때문입니다.

이 정보는 자료형이 차지하는 메모리 저장공간의 크기를 의미하는데요,

예시를 보면 이렇게 저장하는 이유를 좀 더 쉽게 이해할 수 있습니다.

  1. [0x12ff73,0x12ff74,0x12ff75,0x12ff76]
  2. [0x12ff73,4]

두 방법을 비교하면 한 눈에 보기에도 2번 방법이 더 짧고 효율적입니다.

이렇게 저장할 수 있는 이유는 앞서 말했듯이 하나의 변수에 대한 메모리 주소는 연속된 값을 가지기 때문입니다.

1번처럼 주소를 전부 저장하지 않아도 2번처럼 “0x12ff73부터 4개의 주소”로 저장해도 메모리 주소를 전부 표현할 수 있기 때문에 실제 포인터는 2번과 같은 저장 방법을 사용합니다.

다시 소스 코드로 돌아가서 printf("포인터가 가리키는 곳에 저장된 값 : %d\n",*px);를 살펴보겠습니다.

이 문장은 “포인터 변수 px가 가리키는 메모리 공간인 변수 x에 저장된 값을 출력해라!”로 해석이 됩니다.

*px는 포인터 변수 px가 가리키는 변수 x를 의미하는 것이고 그렇기 때문에 정수형 변수의 출력 형식 %d를 이용해 출력해줍니다.

따라서 px포인터 형의 변수이므로 변수(여기선 x)의 주소값 0x12ff73을 갖지만, *px포인터가 가리키는 메모리를 참조하는 int 형의 값 50을 갖는다는 것을 알 수 있습니다.