포인터는 C언어가 가지고 있는 매우 강력한 특징이다. 포인터는 어떤 것을 가리키는 변수라고 할 수 있다.
포인터는 *(asterisk)를 붙여 사용할 수 있다. *는 포인터를 선언할 때, 그리고 포인터가 가리키는 주소안의 값에 접근할 때 사용된다.
int a = 10;
int* p;
포인터의 선언은 위와 같이 사용한다. int형 변수 a를 가리키기 위해 int형 포인터 변수 p를 선언한 것이다.
하지만 포인터 변수p는 현재 어떤 것도 가리키지 않은 상태이다.
integer의 크기는 4byte / float의 크기는 4byte / char의 크기는 1byte 이다.
x64 프로세서에서 한 개의 처리 단위 메모리 주소의 크기는 8byte이고 변수a는 4byte이므로
위와 같이 차지하는 것을 볼 수 있다.
포인터의 크기는 8byte이다. 메모리 공간, 즉 주소를 가리켜야 하므로 8byte의 크기를 갖는 것이다.
메모리의 고유의 주소는 변수마다 각각 다르다.
변수 a의 실제 주소를 구해보면 위와 같이 나오는 것을 알 수 있다.
포인터 변수p를 이용하여 변수a를 가리키려면 p가 a의 주소값을 가지도록 해야한다.
주소는 &(ampersand)를 사용해 입력하고 &a를 입력하면 a의 주소값을 입력한다는 뜻이다.
그렇다면 p의 값을 출력했을 때 a의 주소값 62fe14가 출력되고 *p를 출력했을 때는 p가 a의 주소값을 가리키고 있으므로 *p는 그 주소값 안의 a의 값인 10을 가리키는 것이다. 변수 a의 값을 다른 정수값으로 바꾸어도 *p의 값은 그것을 따르게 된다.
포인터끼리는 연산도 가능하다.
만약 a와 b의 값을 swap() 함수를 이용해 서로의 값을 바꾸고 싶다면 컴퓨터 내에서는 위와 같이 처리해야 한다.
이것을 코드로 표현하면 다음과 같다.
하지만 swap함수를 사용해 a와 b를 적용했음에도 스왑이 이루어지지 않은 것을 볼 수 있다.
이것은 swap함수와 main함수간의 변수가 서로 독립적으로 작용하고 있으며 두 함수간에 어떤 return값도 받고 있지 않기 때문이다.
따라서 swap(int i, int j)에 각각 a와 b의 주소를 넘겨주어야 한다. int i와 int j는 정수형만 받을 수 있으므로 주소를 받을 수 있는 포인터를 사용해야 한다. swap(int* i, int* j)로 입력하여 a와 b의 주소값을 받는다.
또한 temp에는 i의 주소가 아니라 i의 값을 넣어야 하므로 *i를 입력, 마찬가지로 아래에도 *i = *j, *j = temp로 입력한다.
그러면 main 함수의 a와 b의 값이 성공적으로 스왑된다.
배열을 만들어 그 안에 Good을 입력하고 포인터 변수p를 이용해 맨 첫번째 글자의 주소, 즉 0번째 인덱스를 가리키게 한다고 하자.
array 자체는 주소를 가지고 있다. array[0]은 해당하는 값을 가지고 있는 것이다.
그래서 위와 같이 p를 array 이용하듯 사용할 수도 있다.
하지만 만약 1번째 인덱스 o를 출력하기 위해 G가 가지고 있는 메모리 주소에 1을 더한다는 생각으로 *p에 1을 더하면 위와 같이 배열 값에 존재하지 않는 H가 출력된 것을 볼 수 있다.
이것은 연산 우선 순서로 인해 G알파벳의 아스키코드에 1이 더해진 것으로 G다음 알파벳이 H라서 H가 출력된 것이다.
포인터 *는 +보다 계산이 먼저 이루어지므로 (*p) + 1 이 된 것이다.
따라서 연산 순서를 위와 같이 설정하고 출력하면 G다음의 o가 출력된 것을 볼 수 있다.