4-2일 포인터
Shared on April 19, 2026
포인터 개념과 활용 – C 프로그래밍 강의 요약
개요
이 강의에서는 C 언어에서 포인터의 정의, 사용법, 그리고 포인터를 활용한 메모리 접근과 배열과의 관계, 동적 메모리 할당에 대해 설명한다. 포인터를 이해하면 변수에 직접 접근하지 않고도 간접적인 메모리 조작이 가능해지며, 이는 함수 인자 전달, 배열 순회, 동적 데이터 구조 구현 등에서 필수적이다.
핵심 개념
| 개념 | 설명 |
|---|---|
| 포인터 | 메모리 주소를 저장하는 변수. int *iptr;처럼 *를 붙여 선언. |
역참조 연산자(*) | 포인터가 가리키는 주소에 있는 실제 값을 읽거나 쓴다. *iptr = 10; |
주소 연산자(&) | 변수의 메모리 주소를 가져온다. iptr = &i; |
| 포인터 산술 | iptr + 1 은 포인터가 가리키는 다음 정수(4바이트) 위치로 이동한다. -도 마찬가지. |
| 배열과 포인터 | 배열 이름은 첫 번째 요소의 상수 포인터이다. 배열 접근은 arr[3] 와 *(arr + 3)이 동등. |
| 동적 메모리 할당 | malloc(size) 으로 운영체제로부터 메모리 요청, 반환 주소를 포인터에 저장. 사용 후 free(ptr) 로 반환. |
| 스코핑 규칙과 포인터 | 지역 변수는 함수 내부에서만 접근 가능. 하지만 &i 를 인자로 넘겨 포인터를 통해 외부에서 접근 가능. |
상세 내용
1. 포인터 선언과 사용
int *iptr;→ 포인터 변수iptr선언iptr = &i;→i의 주소를iptr에 저장*iptr = 20;→iptr가 가리키는 주소에 20 저장 (i값이 20으로 변경)
2. 간접 접근의 장점
- 함수 인자 전달:
void swap(int *x, int *y) { int t = *x; *x = *y; *y = t; }
swap(&i, &j);로 호출하면 지역 변수i,j를 직접 바꾸지 않고 포인터를 통해 값 교환. - 스코프 회피: 지역 변수를 포인터로 전달하면 함수 외부에서도 값을 조작 가능.
3. 포인터 산술
iptr + 1→ 다음 정수(4바이트) 주소.iptr - 1→ 이전 정수 주소.iptr++/iptr--은 포인터 자체를 이동.
4. 배열과 포인터
- 배열 선언:
int arr[10]; arr은&arr[0]와 동일한 상수 포인터.arr[3]는*(arr + 3)와 동일.- 포인터 변수를 배열처럼 사용해도, 배열 이름은 상수이므로 재할당 불가.
5. 동적 메모리 할당
int *ptr = (int *)malloc(10 * sizeof(int)); // 10개의 int 공간 확보
if (ptr == NULL) { /* 할당 실패 처리 */ }
for (int i = 0; i < 10; i++) ptr[i] = i * 10; // 포인터로 배열 접근
free(ptr); // 사용 후 해제
malloc은 바이트 단위로 요청하므로sizeof로 타입 크기 계산 필요.free를 호출하지 않으면 메모리 누수 발생.
6. 실전 활용 예시
- 배열 초기화
포인터를 이용해for (int i=0; i<10; i++) *(ptr+i) = i*10; - 동적 2차원 배열
int **matrix = malloc(rows * sizeof(int *));
각 행을malloc(cols * sizeof(int))로 할당 후 사용. - 메모리 누수 방지
프로그램 종료 전free호출, 혹은calloc으로 초기화.
7. 자주 발생하는 실수
- 포인터 변수에 비정상적인 주소를 저장 → 프로그램 충돌
- 배열 이름을 변수처럼 재할당 시도 → 컴파일 오류
malloc후 NULL 체크 미흡 → 지연 충돌free이전에 포인터를 다른 주소에 할당 → 메모리 누수
8. 학습 포인트
- 포인터는 변수의 주소를 저장하는 변수이며,
*(역참조)와&(주소연산자)로 사용된다. - 포인터 산술은 메모리 주소 단위(타입 크기)로 계산된다.
- 배열과 포인터는 문법적으로 비슷하지만, 배열 이름은 상수 포인터라 재할당 불가.
- 동적 메모리 할당은 운영체제와의 상호작용이며, 반드시
free로 해제해야 한다.
핵심: 포인터를 이해하면 함수 간 데이터 전달, 배열 순회 그리고 동적 데이터 구조를 효율적으로 구현할 수 있다. 직접 값을 쓰는 것보다 포인터를 통해 간접적으로 접근하면 스코프 제한을 넘어설 수 있다.