포인터는 어떤 변수의 주솟값을 저장한다. 포인터 역시 변수의 자료형을 따라가야 한다.
int n = 100;
int* ptr_n = &n;
여기서 * 은 참조 연산자, & 는 주소 연산자이다.
참조를 한 번 더하면 이중 포인터, 즉 포인터를 가리키는 포인터 또한 만들 수 있다.
int n = 100;
int* ptr_n = &n;
int** ptr_ptr = &ptr;
포인터의 연산에는 몇 가지 정해진 규칙이 있다.
-
포인터끼리의 덧셈, 곱셈, 나눗셈은 아무런 의미가 없습니다.
-
포인터끼리의 뺄셈은 두 포인터 사이의 상대적 거리를 나타냅니다.
-
포인터에 정수를 더하거나 뺄 수는 있지만, 실수와의 연산은 허용하지 않습니다.
-
포인터끼리 대입하거나 비교할 수 있습니다.
만약 포인터에 1을 더한다면 포인터가 가리키는 주솟값은 어떻게 변할까?
그 증가 폭은 포인터가 가리키는 변수의 타입의 크기와 같게 된다.
예를 들어, int형 포인터의 증가폭은 int형 타입의 크기인 4바이트만큼 증가하게 된다.
이 법칙은 포인터의 뺄셈에서도 똑같이 적용된다.
함수를 호출할 때에는 함수에 필요한 데이터를 인수(argument)로 전달해 줄 수 있다.
이렇게 함수에 인수를 전달하는 방법에는 크게 다음과 같이 두 가지 방법이 있다.
-
값에 의한 전달(call by value)
-
참조에 의한 전달(call by reference)
이 중 두 번째인 call by reference 를 포인터를 이용해 구현할 수 있다.
#include <stdio.h>
int main(void)
{
int n = 10;
plus10(&n);
printf("%d", n);
return 0;
}
void plus10(int* p)
{
*p += 10;
}
값에 의한 전달을 했다면 n 의 값이 10 증가하지 않았겠지만(plus10 함수에서 별개의 변수가 됐을 것이므로) 참조에 의한 전달을 했기 때문에 plus10 함수 밖에 있는 변수 n 에 영향을 미칠 수 있다.
배열의 이름은 그 값을 변경할 수 없는 상수라는 점을 제외하면 포인터와 같다. 배열의 이름은 배열의 첫 번째 요소를 가리킨다.
C언어에서는 배열의 이름을 포인터처럼 사용할 수 있을 뿐만 아니라, 포인터를 배열의 이름처럼 사용할 수도 있다.
arr이 배열의 이름이거나 포인터이고 n이 정수일 때,
arr[n] == *(arr + n)
포인터 배열은 배열의 요소로 포인터 값을 갖는 배열이다.
배열 포인터는 배열을 가리킬 수 있는 포인터를 말한다.
배열 이름이 있는데도 따로 배열 포인터를 정의하여 사용하는 이유는 2차원 이상의 배열을 가리킬 때 포인터를 통해 배열과 같은 인덱싱을 할 수 있도록 하기 위함이다.
즉, 포인터를 배열처럼 사용하기 위해서 배열 포인터를 정의하여 사용한다.
따라서 배열 포인터는 1차원 배열에서는 아무런 의미가 없으며, 2차원 이상의 배열에서만 의미를 가진다.