2 분 소요

포인터

정수형이나 실수형의 일반ㅂ적인 변수들은 수치값을 저장한다. 이에 비해 포인터형은 번지를 기억한다는 면에서 일반적인 변수와는 조금 다르다. 데이터가 보관되어 있는 메모리 위치를 기억하고 있기 때문에 직접 값을 조작할 수도 있고 주변의 다른 값까지도 손델 수 있다. 또한 위치는 단순히 4바이트의 번지이기 때문에 함수의 인수로 전달하거나 받기도 효율적이며 함수로 포인터를 전달하면 포인터가 가리키는 메모리를 함수가 직접 조작하는 것이 가능하다.
포인터를 알려면 우선 번지의 개념에 대해 알아야 한다. 컴퓨터의 주 기억 장치(RAM)은 용량이 아주 커서 보통 백만 또는 10억 단위를 사용한다. 컴퓨터에 실제 RAM이 얼마만큼 장착되어 있는가에 상관없이 32비트 운영체제 환경에서 각 프로그램은 32비트의 가상 메모리 공간을 사용할 수 있다. 즉 값을 기억할 수 있는 메모리의 용량은 최대 4G가 된다. 컴퓨터는 메모리의 위치를 구분하기 위해 순서대로 번호를 붙여 관리하는데 이 번호를 번지라고 한다. 최초의 시작 번지는 0번이고 순서대로 1, 2, 3…순으로 40억까지 번지가 붙어 있다. 그래서 컴퓨터는 메모리 중의 특정 바이트를 지칭할 때 이 번지를 사용하여 정확한 위치의 값을 읽고 쓴다.

포인터란 변수의 값이 아닌 변수가 저장되어 있는 메모리의 번지를 기억하는 타입이이다.
포인터는 다음과 같이 선언한다.

타입 *변수명
int *pi

pi는 임의의 정수형 변수가 기억된 번지를 가질 수 있다.
다음 두 연산자는 포인터 변수와 함께 사용되어 번지와 관련된 연산을 한다.

*: 포인터가 가리키는 번지의 값을 읽는다.
&: 변수가 기억되어 있는 메모리 번지를 읽는다.

void main()

{
     int num=629;
     int *pi;

     pi=#

     printf("num의 값은 %d입니다.\n",*pi);

}

결과 : “nume의 값은 629입니다.”

int num = 629; –> 4바이트의 메모리공간 할당, 629라는 값으로 초기화, 번지는 편의상 1234로 표현
int *pi; –> 정수형 변수의 번지를 가리키는 포인터 변수 pi 생성
pi = # –> pi는 num에 기억되어 있는 메모리 번지 1234라는 값을 가지게 된다.

여기까지의 메모리 상황은 다음과 같다.
1
num은 1234번지에 할당되어 있고 629라는 값을 가지고 있다. pi=# 대입문에 의해 1234라는 번지값이 기억되는데 pi는 num이 저장된 번지를 가리키고 있는 것이다. 이 상태에서 *pi로 값을 읽으면 num 변수의 값이 읽혀진다.

2
*연산자는 포인터 변수가 가리키는 번지의 값을 읽는데 pi가 1234번지를 가리키고 있으므로 이 번지로 찾아가 그 값을 읽어온다. pi가 & num의 값, 즉 num의 번지값을 가지고 있는 상황에서는 *pi가 num과 동일하다. num에 어떤 값을 대입하는 문장 대신 *pi= 값; 식으로 대입하는 것도 가능하다.

num 변수를 바로 읽으면 되는데 왜 이렇게 포인터라는 간접적인 방법을 사용하는가? 한단계 더 중간 과정을 거치게 되면 그 중간 과정에서 많은 유용한 조작이 가능해지기 때문이다. 다음 예제는 포인터의 개념을 이해하는데 많은 도움을 준다.

void main()

{
     double num1, num2;
     double *pd;

     num1 = 3.14;
     pd = &num1;
     num2 = *pd;

     printf("num2의 값은 %f입니다.\n",Num2);
}

double num1, num2; –> 8바이트 메모리 점유, 실수형 변수 선언, 번지는 편의상 1234와 5678에 할당
num1 = 3.14; –> num1 값 초기화, num2는 쓰레기값
pd = &num1; –> num1이 할당된 번지값을 대입

이때의 메모리 상황은 다음과 같다.
3
pd가 num1의 번지를 가리키고 있다. 이상태에서 num2 = *pd;를 실행하면 다음과 같은 연산이 수행된다.

4
pd가 가리키고 있는 번지를 먼저 찾아 가고 *연산자로 그 값을 읽는다. 그리고 num2에 값을 대입하였다. 결국 이 예제는 포인터를 통해 간접적인 연산을 하지만 결과적으로는 num2 = num1; 이라는 대입 연산을 하고 있다. 이 예제를 이해하면 포인터의 개념과 *, & 연산자에 대해 이해했다고 할 수 있다.