본문 바로가기
PROGRAMMING/C

C언어 포인터 심화과정 (배열과 포인터, 포인터의 포인터)

by 쪼렙엔지니어 2022. 11. 2.
반응형

자~ 포인터 심화과정 3번째 시간입니다. 포인터에 대해서는 조금 익숙해 지셨나요? 사실 포인터가 C언어에서 가장 난해하고 어려운 부분입니다. 최대한 쉽게 설명하고 있지만 실제로 어려운건 어쩔 수 없죠... 그럴때는 돌파할 수 있는 방법이 한가지 밖에 없습니다. 바로 반복학습이죠. 계속해서 반복하여 코딩을 짜보세요. 똑같거나 비슷한 프로그램도 좋고, 창의적으로 새로운걸 짜도 좋습니다. 반복 숙달하다보면 우리의 뇌는 새로운 걸 갑자기 깨닫기도 하거든요. 

여튼 오늘은 포인터 심화과정 3번째 시간으로 배열과 포인터의 관계에 대해서 알아보려고 합니다. 배열과 포인터의 관계에 대한 내용을 끝내고 나면 그 어렵다는 포인터의 99%를 끝낸 것이니 이번파트까지만 화이팅 해봅시당. ㅎㅎ 그럼 바로 시작해 보겠습니다.

 

1. 배열과 포인터의 관계

먼저 배열에 대해 알아보았던 기억을 더듬어 보겠습니다. 배열은 동일한 자료형의 변수가 많이 필요할 때 그걸 하나씩 선언하지 않고 묶어서 한꺼번에 선언하기 위해서 사용하기 때문에 변수의 집합체라고도 생각할 수 있습니다. 그리고 배열은 메모리상에서 차례대로 위치한다는 특징이 있습니다.

배열의 특징
동일한 자료형인 변수의 집합체
메모리 상에서 순서대로 위치

위에서 얘기한 특징 중에서 메모리상에서 순서대로 위치한다는 건 어떤 의미인지 이해가 되셨나요? 포인터에 대해서 처음 배울때 메모리상의 데이터를 저장하는 공간에는 각각의 주소가 있고 순서대로 나열되어 있다고 이야기 했었죠? 프로그램을 작성할 때 배열을 선언하게 되면 메모리의 어떤 공간에서 시작하여 배열의 크기만큼 순서대로 위치한다는 의미입니다. 보기 편하게 그림으로 나타내면 아래와 같습니다.

우리가 위와 같은 배열을 선언한다고 가정해 봅시다.

그럼 선언된 배열은 메모리 상에서 위 그림과 같이 순서대로 위치하게 된다는 것이죠. 쉽죠? 그렇다면 우리가 변수의 주소를 포인터에 저장하여 접근했던 것처럼 배열도 포인터로 접근할 수 있을까요? 네. 당연히 됩니다. 아래의 간단한 예제를 한번 보도록 하겠습니다.

배열의 주소에 접근해 보는 것은 처음이네요. 위 예제에 나와있듯이 배열의 주소에 접근하는 연산자도 변수의 주소에 접근할 때와 마찬가지로 단항연사자인 "&"을 사용합니다. 그 외에는 변수의 주소를 포인터에 대입할 때와 동일한 내용입니다. 그럼 실행시켜서 결과를 한번 볼까요?

동일한 주소가 출력되는 것을 확인 할 수 있습니다. 깔끔하네요. 그럼 여기서 한발자국 더 나아가서 이전에 배웠던 포인터의 덧셈을 이용해 보겠습니다. 그래서 배열의 순서대로 주소를 출력해 보겠습니다.

위 예제는 for문을 이용하여 배열의 0번 원소부터 10번 원소까지의 주소를 출력하고, 배열의 0번 원소의 주소를 포인터 pa에 대입한 다음 포인터의 덧셈 기능을 이용하여 포인터를 하나씩 증가시켰을 때 배열의 주소와 동일한지 알아보기 위한 예제입니다. 그럼 바로 실행시켜보도록 하겠습니다. 

예상했던것과 같이 동일한 주소가 출력되는 것을 확인 할 수 있었습니다. 자 이렇게 배열을 이용하면 반복되는 동일한 데이터 타입의 변수를 만들 때 한번에 만들 수 있어서 편리했던점과 더불어 포인터로 데이터 저장공간에 접근하기에도 편리해 집니다. 

 

2. 배열 이름의 의미

그런데 말입니다. 여기서 한가지 더 집고 넘어가야 할 사항이 있습니다. 바로 배열의 이름입니다. 본론부터 말하자면 배열의 이름은 배열의 첫번째 원소를 가리키고 있습니다. 즉 배열의 이름은 배열의 첫번째 원소의 주소값이 들어있는 것이죠. 대박 놀랄만한 사건 아닌가요!!! 그렇기 때문에 아래와 같이도 프로그램을 작성할 수 있습니다.

위 예제에서는 &array[0] 이었던 부분을 array로 바꾸었습니다.그래도 정상작동 합니다. 한번 직접 해보시기 바랍니다.

 

3. [ ] 대괄호 연산자

다음으로 우리가 배열에서 사용했던 [ ] 대괄호에 대해서 이야기를 좀 해보도록 하겠습니다. [ ] 대괄호 또한 연산자라는 사실이 매우 놀랍습니다만 예전에 연산자 우선순위에 대해서 알아볼때도 당당히 안에 포함되어 있었습니다. 바로 간단한 예제부터 한번 보겠습니다.

위와 같이 프로그램을 작성하면 실행결과가 모두 동일합니다. 이것은 x[y]라는 형태가 사실은 컴퓨터 내부에서 *(x+y)라는 형태로 바뀌어서 연산을 수행해 나가기 때문입니다. 단항연산자 *(별표)는 해당 주소값이 가리키는 메모리 공간에 존재하는 데이터 값을 출력하지요. 그렇기 때문에 ( ) 소괄호속 연산이 끝난 상태에서 그 앞에 단항연산자 별표가 붙는 꼴이 되는 것입니다. 이해가 되시나요? 

위 2번에서 배열의 이름은 배열의 첫번째 원소(0번 원소)의 주소를 가리킨다고 이야기 했었습니다. 그렇기 때문에 소괄호 속에서 a+1이든 1+a든 연산 결과는 동일하게 첫번째 원소에서 1만큼 더한 두번째 원소를 가리키게 되는 것이고, 거기에 단항연산자 *(별표)가 붙어서 두번째 원소의 데이터 값이 출력되는 것입니다. 이해가 잘 안되는 분은 한번 찬찬히 다시 읽어보시기 바랍니다.

배열을 연산할 때 위와 같이 변환되어 연산됩니다. Array라는 배열의 이름은 배열 첫 원소의 주소값을 가지기 때문에 포인터로 봐도 무방하고 따라서 배열의 이름에 1을 더한다는 것은 포인터에 1을 더한것과 같다고 봐야 합니다. 그리고 단항연산자 *(별표)가 앞에 붙은것이죠. 

 

4. 포인터의 포인터

이제 포인터의 포인터에 대해서 알아보겠습니다. int a; 라고 정의된 변수a를 가리키는 포인터를 int *pa; 라고 하면 int *pa;를 가리키는 포인터는 int **ppa; 라고 쓸 수 있습니다. 예제를 한번 만들어 보겠습니다.

이해가 되시나요? 단순히 단항연산자 &(and)와 *(별표)를 좀 더 응용력 있게 사용함으로 써 변수와 그 포인터, 그 포인터의 포인터까지 연동할 수 있다는 것을 알 수 있었습니다. 오늘은 너무 길어질 것 같으니 여기까지 하고 다음시간에 배열 포인터와, 포인터 배열에 대해서 알아보도록 하겠습니다. 감사합니다.

 

제 블로그를 방문해 주셔서 감사합니다.

도움이 되셨다면 공감(좋아요) 부탁드리고,

댓글은 다른분들께도 좋은 정보일 수 있으니

공개로 부탁드립니다.

여러분의 작은 정성이 좋은 포스팅을 생산하는

힘이 된답니다. :)

감사합니다.

 

 

반응형

댓글