데이터의 주소값이란 데이터가 저장된 메모리의 시작 주소를 의미한다. C언어에서는 주소값을 1byte 크기의 메모리 공간으로 나누어 표현하고, 그 중 4byte의 크기를 갖는 int형 데이터의 주소값은 시작 주소 1byte만을 가리킨다.
포인터(pointer)란 메모리의 주소값을 저장하는 변수로, 포인터 변수라고도 부른다.
int num = 100; // 변수 선언
int *ptr = &n; // 포인터 선언

&(ampersand)는 변수의 이름 앞에 사용하며 해당 변수의 주소값을 반환한다.
포인터의 이름이나 주소 앞에 사용하며 포인터가 가리키는 주소에 저장된 값을 반환한다.
타입* 포인터이름;
타입은 포인터가 가리키고자 하는 변수의 타입을 명시한다. 포인터이름은 포인터 선언 후, 포인터에 접근하기 위해 사용된다.
포인터를 선언한 후 참조 연산자(*)를 사용하기 전에 포인터는 반드시 초기화되어 있어야 한다. 그렇지 않으면 메모리의 값을 변경하게 되기 때문이다. 따라서 포인터의 선언과 초기화를 함께 하는 것이 좋다.
타입* 포인터이름 = &변수이름;or타입* 포인터이름 = 주소값;
int num = 100; // 변수 선언
int *ptr = # // 포인터 선언
int *pptr = &ptr; // 포인터 참조
위의 예제는 포인터의 주소값과 함께 포인터가 가리키고 있는 주소값의 데이터를 참조하는 것이다.

포인터는 값의 증감 연산만 가능하다. C언어의 포인터 연산 규칙을 살펴보자.
- 포인터끼리의 덧셈, 곱셈, 나눗셈은 별 의미가 없음
- 포인터끼리의 뺄셈은 두 포인터 사이의 상대적 거리를 나타냄
- 포인터에 정수를 더하거나 뺄 수는 있으나 실수와의 연산은 허용하지 않음
- 포인터끼리 대입 및 비교 가능함
char* ptr_char = 0;
int* ptr_int = NULL;
double* ptr_double = 0x00;
printf("포인터 ptr_char가 가리키고 있는 주소값 : %#x \n", ptr_char);
printf("포인터 ptr_int가 가리키고 있는 주소값 : %#x \n", ptr_int);
printf("포인터 ptr_double가 가리키고 있는 주소값 : %#x \n", ptr_double);
printf("---------------------------------/n");
printf("포인터 ptr_char가 1 증가 후 가리키고 있는 주소값 : %#x \n", ++ptr_char);
printf("포인터 ptr_int가 1 증가 후 가리키고 있는 주소값 : %#x \n", ++ptr_int);
printf("포인터 ptr_double가 1 증가 후 가리키고 있는 주소값 : %#x \n", ++ptr_double);
위의 예제를 실행시키면 모든 포인터에 저장된 초기 주소값은 0x00임을 알 수 있다. 그러나 1씩 증가시킨 후 포인터가 가리키고 있는 주소는 각각의 포인터 타입에 따라 달라진다.
증가 폭은 포인터가 가리키는 변수의 타입 크기와 같게된다. 즉, int형 포인터 증가폭은 int형 크기 만큼인 4byte씩 증가하게 된다.