포인터는 말그대로 어딘가를 가르킨다는 뜻이다. 보통은 메모리 주소를 가지고 있게 되며 해당 메모리 주소에 값을 써 넣거나 읽어 올때 사용된다. 다음 코드를 보자.
struct {
int a;
int b;
} s;
int *p;
s.a = 1;
s.b = 2;
p = &s.a;
*p = 10;
*(p + 1) = 20;
printf("a=%d, b=%d\n", s.a, s.b);
int a와 int b는 각각 stucture s의 구성요소이다. 위 코드를 수행하게되면 a 값은 10, b값은 20이 된다. 구조체(structure)의 각 변수들은 메모리 상에서 연속적으로 위치 하기 때문에
*(p + 1) = 20;
코드에 의하여 b값이 변경되게 되는 것이다. 이처럼 C에서는 변수를 그 자체 이름이 아니라 포인터를 사용하여 자유롭게 메모리를 변경할 수 있는데 이는 C의 장점이자 단점이다. 장점의 측면으로는 시스템 메모리를 자유롭게 다룰수 있기 때문에 빠른 속도의 코드를 작성할 수 있으며 특히 메모리를 직접 다루어야 하는 그래픽등의 프로그램 종류에서는 매우 유용하다.
그러나 이렇게 주소를 사용하여 직접 메모리를 접근하는 방법은 오류 발생시 오류를 찾아내기 힙들게 만들며 프로그램, 심지어는 시스템 까지도 마비시키는 치명적인 오류를 발생시키는 경우가 많다. 더구나 이렇게 발생된 오류는 찾아 내기도 쉽지 않아서 프로그램 자체를 아예 폐기해야 하는 경우까지 발생할 수 있다.
위의 예제에서 보더라도 단순한 예이기 때문에 b의 값이 변경된 사실을 알 수 있지만 실제 프로그램에서 오류로 인하여 프로그램 어떤 부분에서 b 값을 예제와 같은 방식으로 변경하고 있다면 프로그램을 만든 사람조차도 그 위치를 찾아내기가 어렵게 된다. 왜냐하면 소스에서 b를 접근하는 모든 코드를 검사해도 나오지 않기 때문이다. 즉 b를 사용하지 않고 b를 변경했기 때문이다.
C, C++ 이후에 나온 고차원의 언어들 JAVA, C#등은 이러한 접근을 원천적으로 차단하고 있으며 사용하려면 다소 복잡한 선언을 통해서만 가능하도록 하고 있다. 아무튼 포인터는 C만이 가지는 고유한 기능이며 거의 모든 C 코드들은 포인터로 구성되어 있다해도 과언이 아니므로 포인터에 대한 이해는 필수적이라 하겠다.