다중 포인터와 배열 포인터

'혼공 C언어' 15-1강 이중 포인터와 배열 포인터

by Younggi Seo





n 포인터의 개념을 확실히 숙지하려면, 대입 연산자(=)를 기준으로 좌측에 들어갈 수 있는 값과 우측에 들어갈 수 있는 값의 규칙을 알아야 한다.



(l-value) = (r-value)



좌측에는 변수가 올 수 있다. 즉, 어떤 값의 형태(상수)가 위치해서는 안된다. 왜냐하면 좌측은 어떤 값을 담기 위한 공간을 의미하기 때문이다. left 값을 l-value라 하고, 여기에는 간접참조 연산자(*)가 쓰인 포인터가 올경우, 포인터가 가리키는 주소에 담겨있는 값(r-value)이 아니라 '포인터 변수가 가리키는 변수'를 의미한다. 가리키는 변수에 담길 값은 오른편(right)에 오고 만약, 오른편에 간접참조 연산자가 붙은 포인터 변수가 오면 그 포인터 변수가 가리키는 변수의 값, 즉 상수(프로그램 실행 간 변하지 않는 값)다. 이 right 값을 r-value라고 한다.


int a = 10; // 변수 a의 선언과 초기화
int* p; // 포인터 변수 p의 선언 (int는 포인터 변수의 자료형*이 아니라, 가리키는 자료형을 의미)

p = &a; // 포인터 변수 자체에 a변수의 주소 값 저장


*포인터 변수의 자료형은 포인터형(ARM 32bit 시스템은 4byte)이다.



p (포인터 변수)에 *연산자(간접 참조 연산자)를 붙였을 때의 l-value와 r-value

*p = *p + 30; // 좌측의 포인터 변수 p는 가리키는 변수의 공간을 의미.

// 우측의 포인터 변수 p는 가리키는 변수의 값(10)을 의미.


p (포인터 변수) 자체의 l-value

p = &a; // 좌측의 포인터 변수 자체는 변수 a의 주소 값을 담는 변수로 일반 정수를 담는 변수가 아님.

printf("%p", p); // 출력값은 포인터 변수 p에 저장된 값은 p가 가리키는 변수(a)의 첫 번째 주소 값.


필수 개념


포인터가 어려운 까닭은 포인터의 용도가 위와 같이 4가지로 나뉘기 때문이다. 즉 포인터변수(*p)는 아까 말한 대입연산자 기준으로 왼쪽에 오면 변수(포인터 변수가 가리키는 변수와 동일)의 역할을 하고, 오른쪽에 오면 상수의 역할(가리키는 변수의 값)을 하는데 포인터 연산(& 주소 값, * 간접 참조)을 수행하려면 우측 편에 두어 '주소 상수(constant)'로 사용되어야 한다는 것을 염두에 둬야 한다. 또한 배열 포인터(배열 전체 '시작 주소 값'을 가리키는 변수)로써 포인터 연산을 하려면, 주소 상수(ary[0])를 사용해야지 배열 전체 변수(ary)를 사용하면 안 된다.


char ary[80]; // 배열 선언
ary = "apple" // 배열 전체 변수에 문자열 대입 (컴파일 에러 뜸)
-> ary 배열 전체의 첫 번째 요소의 시작 주소 값에 "apple" 대입

100 = "apple" // 위의 초기화와 같은 의미의 대입
( ary 배열이 메모리 100번지부터 할당되었다고 가정 하)
-> 대입 연산자 왼쪽에 배열명이 올 수 없다!


이중포인터와 배열 포인터 강의
강좌 핵심 요약

포인터의 주소는 이중 포인터에 저장한다.

2중 포인터는 포인터의 값을 바꾸는 함수의 매개변수나 포인터 배열을 매개변수로 받는 함수에 사용한다.

배열의 주소는 배열 포인터에 저장한다.

배열 포인터를 매개변수에 쓰면 함수에서 2차원 배열처럼 사용한다.


이중, 삼중, 사중, 다(n)중 포인터로까지 개념을 확장하면 포인터의 재귀*와 같은 느낌이 든다. 복잡하기는 한데, 계속해서 변수의 주소 값을 가리킨다는 것은 변함이 없다. 그리고 이 다중 포인터를 사용하는 목적이 함수의 매개변수나 포인터 배열을 매개변수로 받는 함수에 사용되는 거와 이전 13-2강에서 배운 '함수의 데이터 공유 방법'에서의 포인터 역할(원본 데이터를 변경하지 않고 주소 값의 교환을 통해 값의 변경이 가능, Call by reference)과 동일하다. 즉, 매개변수(지역 변수의 한 종류)는 스택 메모리에 일시적으로 할당되어 사용되므로 여기에 변수의 값과 주소 값들을 저장시키고 사용한 뒤에는 메모리 공간이 회수된다. 이 때문에 메모리 공간을 재활용할 수 있다.


첨부한 동영상 강좌를 통해 다중 포인터와 배열 포인터까지의 설명을 여러 번 이해하고 자신이 직접 다시 설명해서 개념을 숙지하는 게 중요한 파트다. 오늘이 4월 3일(실기 시험일 2주 남기고)인데, 정처기 실기 기출문제 중 포인터 관련 문제 5개를 추려서 풀어봤는데, 1개 빼고 다 맞추니 개념정립은 된 거 같다.


하지만, 배열 포인터를 사용한 2차원 배열의 구조에서 참조연산자를 사용하는 거에 따라 오프셋(열) 이동이 되기도 하고 인덱스(행) 이동이 되기도 하는데 이게 '응용 포인터'의 개념 중 백미가 아닌가 싶다. C언어는 포인터의 모든 개념을 완전히 숙지하면, 사실 90%는 정복했다고 해도 과언이 아니다.



5가지 키워드로 끝내는 이중포인터와 배열 포인터의 핵심


1. 포인터도 하나의 변수이므로 그 주소가 있다.

2. 이중 포인터에 간접 참조 연산자 *를 사용하면 단일 포인터가 된다.

3. 2차원 배열의 배열명은 첫 번째 부분배열의 주소가 된다(포인터 변수와 동일).

4. 배열 포인터에 간접참조 연산자를 사용하면 가리키는 배열이 된다.


'혼자 공부하는 C언어'의 15-1강의 소스코드를 직접 참고하려면 아래 필자의 깃헙(github)에서 직접 다운로드할 수 있다.



* 재귀 : https://brunch.co.kr/@younggiseo/333


keyword