F.R.I.D.A.Y.

포인터와 배열 본문

DEV/C C++

포인터와 배열

F.R.I.D.A.Y. 2020. 1. 24. 22:25
반응형

 

 

배열 변수의 이름이 0번 인덱스의 시작 주소인 이유

이번 포스트는 제목 그대로 배열 변수의 이름이 어째서 해당 배열의 0번 인덱스의 주소가 되는지 알아봅니다. 간단해요! int arr[10]; &arr[0]; // 처음 배울 때 주로 사용하는 0번 인덱스의 주소를 가져오는 법..

pang2h.tistory.com

 위 글에서는 배열의 첫 요소의 주소는 해당 배열의 이름임을 간단히 설명하고 있습니다. 어째서 이런 결론이 나오게 되는지, 어떤 배경이 있었는지 알아보겠습니다.

 

# 여기에서 (정적)배열은 소스코드에 직접 배열 문법으로 선언된 자료형을 말합니다.


태초에 포인터가 있었다

 께서 세계를 만들 때 법칙을 몇 가지 만들었으니, 그중 하나가 법칙이라.
 이 법칙은 널리 사용되어야 했으며 충분히 많은 곳에서 이로울 법칙 이리다.
 또한, 법칙은 이해하기 어려워 소수만이 법칙의 진리를 깨닫고 제 힘으로 사용할 수 있음이다.
 이 모습을 가여워 한 신께서 대리자를 내려 보내나니, 세상이 이로워지더라.

 우스갯소리로 지어본 말입니다. 그래도 포인터와 배열의 상관관계를 설명하고자 했던 취지는 잘 반영되어있다 생각합니다.

 

 말 그대로, 포인터는 어린 개발자들에게는 어려운 문법입니다. 그래서 데니스 리치는 생각했습니다.

 "조금 더 쉽게 포인터의 기능을 사용하게 할 수는 없을까?"

 고심 끝에 나온 문법이 바로 배열입니다.

 배열은 포인터처럼 유용하게 사용할 수 있습니다. 그러나 포인터 문법을 보다 쉽게 사용하기 위해 나온 문법이다 보니 기능의 제약이 들어가고 그만큼 자유도가 떨어지는 문법입니다.


배열의 사용

 배열이 포인터의 기능을 약화시켜 나온 문법이니만큼, 포인터의 일부 표현을 사용할 수 있게 됩니다. 포인터가 가리키는 대상의 값을 가져오려고 하면 우리는 아래와 같이 코드를 작성해야 한다고 했습니다.

 

Problem. M(2,4)[# M=메모리\n(x, y)]의 위치에 존재하는 값 가져오기

// pointer style
*(*(p + 4) + 2);

 모르는 사람이 보면 어떤 걸 의미하는지 잘 모를 것입니다. 그러나 배열의 표현 방식을 보면 얘기가 달라집니다.

// array style
arr[4][2];

 프로그래밍을 모르는 사람이 보더라도 배열 스타일은 어느 정도 유추해 이해할 수 있을 것입니다.

 

 이 과정에서 가장 중요한 것은 연산자의 문제였습니다. 연산자 자체가 어렵고, 우선순위에서도 뒤쪽으로 밀려있기에 연산 과정을 알기가 어려웠습니다. 그래서 대괄호 연산자를 개발하게 되었습니다.

 

 대괄호 연산자는 아래와 같이 사용할 수 있습니다. 이미 알고 계시겠지만요.

arr[4][2];

 대괄호 연산자 앞에 변수의 이름을 작성하고 대괄호 안에는 접근하고자 하는 인덱스를 작성해줍니다. 그러면 위 포인터 스타일과 같이 동작하도록 합니다.

 1차원 배열을 기준으로 하면 아래와 같겠죠.

 

Problem. 1차원 배열의 세 번째 요소에 접근하기.

// pointer style
*(arr + 2);


// array style
arr[2];

 

 언어 개발자들은 사람들이 기존에 통용해 사용하던 문법을 지키려고 합니다. 그래야 자신이 개발한 언어가 부흥하고 생태계에서 살아남을 수 있을 테니까요.


포인터 스타일과 배열 스타일 번갈아 쓰기

 배열 자체가 포인터에서 나온 문법이다 보니 포인터 스타일을 배열에 적용할 수 있습니다. 또한, 배열 스타일은 편리하기에 포인터에서도 배열 스타일을 이용할 수 있습니다.

 

 그렇다면 본론으로 돌아와서, 배열의 첫 번째 요소 주소가 어째서 배열 변수의 이름인지를 알아보겠습니다.

 

주소 연산자, 간접 참조 연산자

 일반 변수의 주소가 궁금할 때는 변수 이름 앞에 주소 연산자 &를 붙여 알아봅니다. 또한, 특정 주소를 가진 메모리의 값을 보고 싶다면 간접 참조 연산자 *를 붙여 알아봅니다.

변수 var (0x100)

그렇다면 생각해보겠습니다. 위와 같이 변수 이름 var[# 편의를 위해 int타입으로 생각하겠습니다.]로 명명된 공간이 존재합니다. 이 공간의 주소는 0x100입니다. 이 공간의 값을 가져오려면 어떻게 해야 할까요?

printf("%d", var);

 이렇게 생각할 수 있습니다. 그러나 위에서 말한 것처럼 주소를 알고 있다면 간접 참조 연산자를 이용해도 됩니다.

printf("%d", *0x100);

 우리는 이 둘을 섞어볼 수도 있습니다.

printf("%d", *(&var));

 var에 주소 연산자를 붙여 var로 명명된 공간의 주소를 가져왔고, 해당 주소에 간접 참조 연산자를 사용해 값을 가져왔습니다.

 그리고 0을 더해봅시다. 0은 더해도 빼도, 원래 값이 변하지 않지만요.

printf("%d", *(&var + 0));

 어디서 많이 본모습 아닌가요? 바로 위에서 설명한 포인터 스타일입니다.

// pointer style
*(arr + 2);

 var 앞에 붙는 주소 연산자는 var가 일반 변수이기 때문입니다.

 

 각 변수는 대응되는 하나의 공간을 가리켜야 합니다. 그러나 배열의 경우 하나의 이름으로 여러 공간에 접근할 수 있습니다. 어느 요소를 선택 해야하는지 모호할 수 있습니다. arr 자체는 요소의 시작을 가리키고 뒤에 대괄호 연산자를 통해 offset을 지정해주는 것입니다.

 무엇보다 배열 변수의 이름이 첫 요소의 주소를 반환하는 것은 언어가 그렇게 지정했기 때문입니다. 앞서 설명한 내용들은 조금이라도 더 쉽게 이해할 수 있기를 바라며 작성했습니다.


이해하지 못해도 괜찮아요

 C에서 배열 변수의 경우에는 그 변수의 이름이 첫 요소의 주소를 반환한다는 것만 기억하기 바랍니다.


더 알아보기

 

다차원 배열의 요소 값 교환하기

배열을 만들게 되면 다차원 배열을 만들기도 합니다. 종종 각 요소의 값을 변경해야 하는 경우도 존재합니다. 배열 연산자로 만든 정적 배열과, 포인터와 동적 할당을 이용해 만든 동적 배열을 비교해봅니다. 다..

pang2h.tistory.com

# index

728x90
반응형

'DEV > C C++' 카테고리의 다른 글

포인터 배열? 배열 포인터?  (0) 2020.01.26
다차원 배열의 요소 값 교환하기  (0) 2020.01.25
Designated Initializer  (0) 2020.01.21
배열(array) part2. 다차원 배열  (0) 2020.01.20
배열(array) part1. default  (1) 2020.01.19
Comments