본문 바로가기

프로그래밍 언어/C

C언어 변수 심화, 포인터와의 관계 이해하기

C언어 변수 심화, 포인터와의 관계 이해하기

C언어의 변수는 단순히 값을 담는 상자가 아닙니다. 포인터(pointer)와 얽히기 시작하면 변수는 메모리의 주소를 다루는 복합적인 구조로 진화합니다. 본 글에서는 C언어 변수의 메커니즘을 심화 수준으로 파헤치고, 포인터와의 유기적인 관계를 다양한 사례와 시각적 구성으로 해부해봅니다.

 

 

목차

  1. 변수와 메모리 주소의 본질
  2. 포인터란 무엇인가?
  3. 포인터 변수 선언과 초기화
  4. 주소 연산자와 역참조 연산자
  5. 일반 변수와 포인터의 연동 구조
  6. 포인터 안전성과 위험 요인
  7. 실전 응용: 배열, 함수 인자, 동적 할당

 

1. 변수와 메모리 주소의 본질

C언어에서 변수는 메모리 공간에 대한 이름입니다. 변수 선언 시 컴파일러는 메모리의 특정 위치에 공간을 할당하고 그 주소를 기억합니다.

  • int a = 10; → 변수 a정수 10을 저장
  • 그러나 실제로는 메모리 어딘가에 존재하며, 주소가 부여됨

다음은 변수와 메모리 간 구조를 도식화한 예입니다.

이름 주소
a 0x7ffee123 10

 

 

 

2. 포인터란 무엇인가?

포인터는 변수의 주소를 저장하는 특수한 변수입니다. 단순히 값(value)이 아닌 위치(location)를 다루는 개념이므로, 메모리 중심 프로그래밍에 핵심이 됩니다.

int *p; // int형 변수의 주소를 담는 포인터
  

 

 

 

3. 포인터 변수 선언과 초기화

포인터 변수는 *를 통해 선언되며, 반드시 정확한 타입과 함께 사용해야 합니다.

int a = 20;
int *p = &a; // a의 주소를 p에 저장
  
  • &a는 변수 a의 주소
  • p는 주소를 저장하는 변수, 즉 포인터

 

 

 

4. 주소 연산자와 역참조 연산자

C언어의 핵심 연산자 두 가지:

  • 주소 연산자 (&): 변수의 주소를 반환
  • 역참조 연산자 (*): 포인터가 가리키는 메모리의 값을 반환
printf("%d", *p); // a의 값을 출력
  

 

 

 

 

5. 일반 변수와 포인터의 연동 구조

포인터는 변수와 1:1 참조 관계를 맺을 수 있으며, 이를 통해 변수의 값을 간접적으로 제어할 수 있습니다.

  • 포인터를 통해 값을 수정 가능
  • 메모리 주소 간 이동 및 연산 가능
*p = 100; // a의 값을 100으로 변경
  

 

 

 

6. 포인터 안전성과 위험 요인

포인터는 강력하지만 위험한 도구입니다. 잘못 사용하면 다음과 같은 문제가 발생할 수 있습니다.

  • 초기화되지 않은 포인터 접근
  • NULL 포인터 역참조
  • 해제된 메모리에 접근 (Dangling pointer)
  • 잘못된 타입 캐스팅

주의: free() 후 포인터는 반드시 NULL로 설정해야 합니다.

 

 

 

7. 실전 응용: 배열, 함수 인자, 동적 할당

포인터는 다양한 실전 상황에서 핵심 역할을 합니다.

✔ 배열과 포인터

  • int arr[5]int *로 암묵 변환
  • *(arr + i)arr[i]와 동일

✔ 함수 인자로 활용

void modify(int *p) {
  *p = 50;
}
  

✔ 동적 메모리 할당

int *ptr = (int *)malloc(sizeof(int) * 5);
if (ptr != NULL) {
  ptr[0] = 1;
  free(ptr);
}