글 목록으로 돌아가기

C 언어 변수, 포인터, 이중 포인터, 포인터 배열 정리

C 언어에서 변수는 메모리 공간이라는 관점으로 보고, 포인터와 이중 포인터, 포인터 배열의 의미를 정리한다.

JUHOSEOK
JUHOSEOK 2026년 4월 11일 · 3분 읽기
C Pointer Memory Array jungle

변수의 의미

C 언어에서 변수는 단순한 이름표가 아니라, 값을 저장하기 위한 메모리 공간 자체로 볼 수 있다.

  • 변수를 선언하면 메모리 공간이 생성된다.
  • 그 공간에 정수, 문자, 구조체 같은 실제 값이 저장된다.

예를 들어:

int a = 5;

위 코드는 a라는 이름의 정수형 메모리 공간을 만들고, 그 안에 5를 저장한다.

포인터

포인터는 주소를 저장하기 위한 변수다.

& 연산자

&는 어떤 변수의 주소를 구하는 연산자다.

int a = 5;
printf("%p", (void *)&a);

이 코드는 변수 a가 저장된 메모리 주소를 출력한다.

*의 두 가지 의미

*는 문맥에 따라 의미가 달라진다.

  1. 선언에서의 * 포인터 변수를 선언할 때 사용한다.
int *p = &a;

위 코드는 int를 가리키는 포인터 변수 p를 선언하고, a의 주소를 저장한다.

  1. 사용에서의 * 역참조를 할 때 사용한다.
printf("%d", *p);

p 안에 들어 있는 주소를 따라가서, 그 위치에 저장된 실제 값을 읽는다.

역참조

역참조는 주소를 담은 변수에서, 그 주소가 가리키는 실제 메모리 공간으로 다시 찾아가는 동작이다.

int a = 5;
int *p = &a;

printf("%d\n", *p);

결과:

5

흐름은 이렇게 이해하면 된다.

  • p에는 a의 주소가 저장되어 있다.
  • *p는 그 주소로 이동한다.
  • 그 주소에 저장된 실제 값 5를 읽는다.

이중 포인터

이중 포인터는 포인터 변수의 주소를 저장하기 위한 포인터다.

int a = 5;
int *p = &a;
int **p2 = &p;

각 변수의 의미는 다음과 같다.

  • a는 정수 값을 저장하는 변수
  • pa의 주소를 저장하는 포인터
  • p2p의 주소를 저장하는 이중 포인터

즉, 저장 관계를 보면 다음과 같다.

a   <- 실제 정수 값 저장
p   <- a의 주소 저장
p2  <- p의 주소 저장

별의 개수와 저장 대상

저장하려는 대상보다 *가 하나 더 많아야 그 주소를 저장할 수 있다.

int a = 5;
int *p = &a;
int **p2 = &p;
int ***p3 = &p2;
  • pa를 가리킨다.
  • p2p를 가리킨다.
  • p3p2를 가리킨다.

즉:

  • *pa
  • **p2a
  • ***p3a

처럼 더 깊게 역참조할 수 있다.

포인터 배열

포인터 배열은 포인터 변수를 여러 개 배열 형태로 관리하는 구조다.

예를 들어 다음 두 코드는 비슷하게 보일 수 있다.

int *p1, *p2, *p3, *p4, *p5;
int *p[5];

둘 다 int를 가리키는 포인터 5개를 만든다는 점에서는 비슷하지만, 자료구조는 다르다.

  • 첫 번째는 서로 독립적인 포인터 변수 5개
  • 두 번째는 포인터를 원소로 가지는 배열 1개

일반 배열과 포인터 배열 비교

일반 정수 배열은 값을 직접 저장한다.

int arr[5] = {1, 2, 3, 4, 5};

printf("%d\n", arr[0]);

반면 포인터 배열은 주소를 저장한다.

int a = 1;
int b = 2;
int c = 3;
int d = 4;
int e = 5;

int *arr[5] = {&a, &b, &c, &d, &e};

printf("%d\n", *arr[0]);

여기서:

  • arr[0]a의 주소
  • *arr[0]은 그 주소에 저장된 실제 값 1

즉 포인터 배열의 값을 사용할 때는, 주소만 보고 싶다면 arr[i], 실제 값을 읽고 싶다면 *arr[i]처럼 역참조해야 한다.

포인터가 가리킨다는 의미

포인터가 어떤 대상을 가리킨다는 것은, 그 변수가 특정 메모리 주소를 저장하고 있고, 그 주소를 통해 실제 데이터에 접근할 수 있다는 뜻이다.

즉:

  • 포인터는 주소를 저장한다.
  • 역참조는 그 주소를 따라가 실제 값에 접근한다.
  • 이중 포인터는 포인터의 주소를 저장한다.
  • 포인터 배열은 여러 주소를 배열 형태로 관리한다.

정리

  • 변수는 값을 담는 메모리 공간이다.
  • 포인터는 주소를 저장하는 변수다.
  • &는 주소를 구한다.
  • *는 선언에서는 포인터 타입을 뜻하고, 사용에서는 역참조를 뜻한다.
  • 이중 포인터는 포인터의 주소를 저장한다.
  • 포인터 배열은 여러 포인터를 배열로 묶어 관리한다.

처음에는 *&가 헷갈리지만, “값”, “주소”, “그 주소를 다시 따라가는 것”을 구분해서 보면 훨씬 이해하기 쉬워진다.