|

C언어 배열 포인터와 포인터 배열 차이: 이름이 비슷한데 왜 완전히 다를까

배열 포인터와 포인터 배열 차이 대표 이미지
괄호 위치 하나가 선언 의미를 완전히 바꾼다

배열 포인터와 포인터 배열 차이는 C 언어에서 가장 헷갈리는 문법 중 하나입니다. 이름이 너무 비슷해서 비슷한 개념처럼 느껴지지만, 실제로는 메모리 구조와 사용 방식이 완전히 다릅니다.

이번 글에서는 이 주제를 선언 문법 암기로 풀지 않고, 무엇이 배열이고 무엇이 포인터인지부터 메모리 구조로 구분하는 방식으로 설명하겠습니다. 괄호 하나가 왜 선언 의미를 완전히 뒤집는지도 함께 보겠습니다.

배열 포인터와 포인터 배열 핵심 카드
핵심 판단 기준을 먼저 잡는 요약 카드

선언 규칙의 공식 기준은 cppreference의 C pointer 설명을 참고할 수 있습니다. 다만 입문 단계에서는 우선순위 표보다 메모리 그림이 훨씬 도움이 됩니다.

배열 포인터는 무엇인가

배열 포인터는 배열 하나 전체를 가리키는 포인터입니다. 예를 들어 int (*p)[5]는 int 5개짜리 배열을 가리키는 포인터입니다.

즉 p 자체는 포인터 하나이고, 그 포인터가 가리키는 대상이 배열 전체라는 뜻입니다. 따라서 *p를 하면 배열 하나가 나오고, (*p)[i]처럼 접근합니다.

int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;

printf("%d\n", (*p)[2]); // 3

실전에서 포인터 배열이 자주 등장하는 대표 예시는 문자열 목록입니다. 예를 들어 여러 단어의 시작 주소를 보관할 때는 char *words[] 같은 형태가 자연스럽습니다. 각 칸이 서로 다른 문자열을 가리킬 수 있기 때문입니다.

문자열 목록에서 포인터 배열을 쓰는 실전 예시 카드
실전에서는 포인터 배열이 문자열 목록 같은 구조에서 자주 등장한다

포인터 배열은 무엇인가

포인터 배열은 말 그대로 포인터 여러 개를 원소로 가진 배열입니다. 예를 들어 int *arr[5]는 int를 가리키는 포인터 5개를 담는 배열입니다.

즉 arr 자체가 배열이고, 각 원소 arr[i]가 포인터입니다. 그래서 메모리 안에는 포인터가 여러 칸 들어 있는 구조가 됩니다.

int a = 10, b = 20, c = 30;
int *arr[3] = {&a, &b, &c};

printf("%d\n", *arr[1]); // 20
배열 포인터와 포인터 배열 비교 카드
둘의 구조와 접근 방식 차이를 비교한 카드

왜 괄호 하나가 이렇게 중요할까

선언을 읽을 때는 무조건 왼쪽에서 오른쪽으로만 읽지 말고, 변수 이름에서 시작해서 결합 우선순위를 따라가야 합니다. 이 습관이 없으면 비슷한 선언이 나올 때마다 다시 외워야 합니다.

C 선언은 우선순위가 있습니다. []가 *보다 더 강하게 결합하기 때문에, int *arr[5]는 먼저 arr[5]가 배열이라는 뜻이 되고, 그 배열 원소 타입이 int*가 됩니다. 반면 int (*p)[5]는 괄호가 먼저 p를 포인터로 묶어주기 때문에, p가 배열을 가리키는 포인터가 됩니다.

즉 괄호는 단순 장식이 아니라, 무엇이 먼저 결합되는지를 바꿔 선언 의미를 완전히 뒤집는 역할을 합니다.


초보자가 실제로 많이 틀리는 상황은 선언을 읽을 때입니다. int *arr[5]를 보고 배열을 가리키는 포인터라고 오해하거나, int (*p)[5]를 보고 포인터 여러 개가 들어 있는 배열처럼 느끼는 경우가 많습니다. 둘 다 비슷해 보이지만, 주어가 배열인지 포인터인지부터 다시 봐야 합니다.

입문자가 특히 헷갈리는 이유

  1. 이름이 너무 비슷하다
  2. 둘 다 포인터와 배열이라는 단어가 들어간다
  3. 선언을 왼쪽에서 오른쪽으로만 읽으려 하면 잘 안 보인다
  4. 메모리 구조를 안 보고 문법만 외우면 바로 꼬인다

그래서 이 주제는 문법 규칙보다 그림이 더 중요합니다. 배열 포인터는 포인터 1개가 배열 전체를 가리키고, 포인터 배열은 배열 칸마다 포인터가 들어 있다고 보면 훨씬 덜 헷갈립니다.

기본 포인터 감각은 포인터 입문 글, 층 구조 감각은 이중 포인터 글과도 이어집니다.


배열 포인터와 포인터 배열 읽는 순서 도식
선언을 어떤 순서로 읽으면 덜 헷갈리는지 정리한 도식
배열 포인터와 포인터 배열 메모리 비교 카드
메모리 구조 관점에서 다시 비교한 카드
배열 포인터와 포인터 배열 선언 오해 비교 카드
초보자가 선언을 읽을 때 어디서 꼬이는지 비교한 카드

마무리

배열 포인터와 포인터 배열 차이는 이름이 아니라 구조를 봐야 잡힙니다. 하나는 포인터 하나가 배열 전체를 가리키는 구조이고, 다른 하나는 배열 원소들이 각각 포인터인 구조입니다.

무엇이 배열이고 무엇이 포인터인지, 그리고 괄호가 결합 순서를 어떻게 바꾸는지만 분명히 잡으면 이 주제는 훨씬 덜 무섭게 보입니다.

함께보면 좋은 글