포인터, 더 엄밀한 포인터

A pointer is a variable that contains the address of a variable
- K&R C, second edition (1988)

포인터는 변수의 주소를 담은 변수다. 그 이상을 논의하기 이전에 먼저 알아볼 것이 있다.

int *pa;

우리는 기초로 돌아와, 위의 코드가 문법적으로 무엇을 의미하는지 다시금 상기해볼 필요가 있다. 기본적으로 C의 문법 체계에서 변수의 선언은 다음의 문법형식을 따른다.

type name

nametype형임을 선언하는 코드다. 그렇다면, int *pa는 무슨 의미일까? 똑같이, *paint형임을 명시한다. (K&R C는 이에 대해 이러한 문법이 mnemonic하다고 설명한다)

int *pa, *pb;

*pa형이 int임을 명시했기에 paint의 포인터가 되는 것이지, pa형이 int*형이기에 *paint형인것은 아니다. 원인과 결과가 역전된 꼴이다. *가 형식 뒤에 붙지 않고, 변수 선언 앞에 붙는 이유중 하나다.

연산

int* pa;

pa + 1;
*(pa + 1);

3, 4번째줄을 보면, pa에 정수를 더하는 모습인데, 이는 어셈블리어에서처럼 1바이트씩 더함이 아닌, *pa의 자료형의 크기, 즉 4(전형적으로) 바이트씩 더해주게 된다.

int* pa;

pa - 1;
*(pa - 1);

마찬가지로, 뺄셈도 정의된다. *pa의 자료형의 크기, 즉 4(전형적으로) 바이트씩 빼주게 된다.

마지막으로, 포인터와 포인터간의 뺄셈이 정의된다. 포인터와 포인터 사이에 얼마나 많은 공간이 존재하는지 알려준다.

예외

딱 하나 예외가 있는데, 바로 void*형이다.

K&R C에서 소개하기를, void*형은 generic한 포인터로, 기본적으로 직접 역참조 할 수 없다.

K&R C는 memcpy, memset등 generic한 포인터가 필요한 구간에서 char*를 사용하지 말고, void*를 사용하기를 권장하고 있다.

용어 정리

int *pa;

위처럼 선언된 변수 pa를, pa is a pointer to int라고 부르며, 한국어로 pa는 int형의 포인터라고 부른다.

pa = &a;

pa points to a라고 부르며, 한국어로 paa를 가리킨다고 부른다.

*pb = *pa;
*pa = 0;

위처럼 *포인터변수 (본 코드에서는 *pa)와 같이 작성하는 것을 indirection(간접참조) 혹은 dereferencing (역참조)라고 부른다.