<aside>
✳️ 굉장히 헷갈리는 포인트 중 하나다. const int *p, int *const p. 도대체 무슨 차이일까. 심지어 const int * const p까지 된다니 정신이 혼미해진다.
</aside>
쉽게 시작해 보자.
int i = 1;
int *p = &i;
우리가 매일 보던 기본 형태의 포인터다. 특별한 건 없어 보이는데, 만약 i를 const로 바꾸면 어떻게 될까?
**const** int i = 1;
int *p = &i;
에러가 발생한다. 왜일까?
만약에 그 아래에 *p = 2 이라고 코드를 짠다면 포인터를 통해 const로 정의된 i의 값을 바꿀 수 있게 되므로 말이 안 된다. 애초에 컴파일 단계에서부터 막아야 한다.
const int i = 1;
const int *p = &i;
이제 제대로 작동한다. 이제는 const int에 대한 포인터이로 *p = 2처럼 포인터를 따라가 값을 바꾸는 불법 행위는 일어날 수 없다. 보기 편하게 괄호로 묶는다면, (const int) *p이다. 이렇게 보면 이해가 잘 된다.
다시 원래 코드에서 p가 가리키는 주소가 바뀌지 않으려면 어떻게 해야 할까?
int i = 1;
int * const p = &i;
이렇게 쓰면 포인터가 const로 된다. 이제 p = &j와 같이 가리키는 값을 바꿀 수 없다. 괄호로 묶어 보면, int * (const) p가 되겠다.
이제 이 두 개념을 이해했으면 나머지는 덤이다.
const int ** const p 처럼 괴물같은 문법도 이해가 된다. 다만 이런 문법을 실제로 써야 한다면 typedef를 만드는 것이 정신건강에 좋을 것 같다. 리눅스 커널에서는 const int * const p까지는 보인다.