[C언어] # 6. C언어의 꽃, 포인터 (Pointer)에 대한 쉬운 이해

Crush_on_Study·2022년 6월 8일
0

C언어 기초

목록 보기
7/11

포인터 (Pointer)

point! 가리키다

이름 그대로, 포인터는 해석하면 '가리키고자 하는 것'입니다.

사진이 꽤 크네요 ㅎㅎ. 포인터를 단 한장으로 설명한다는 재밌는 짤인데 정말 맞는 말이긴 합니다.


근데, 포인터가 왜 필요한건가요?

시험을 앞둔 여러분들은 공부를 잘하는 친구한테서 도움을 받고자 합니다.
(여러분들이 공부를 이미 잘하셔도 일단 그렇다 칩시다)
공부를 잘하는 친구는 여러분들께 개념을 설명해주기 위해 교재를 함께 참고하면서 필기를 하며 설명을 해줍니다.

근데, 배운 내용을 토대로 복습을 하려하니 기억이 나질 않습니다. 그래서 여러분들은 다시 공부를 잘하는 친구에게 재도움을 요청합니다.

그럼 공부 잘하는 친구는 앞에서 했던 모든 행동들을 다시 한번 하게 됩니다.
물론, 착한 친구라면 그렇겠지만 나쁜 친구의 경우 "내가 이걸 왜 또?" 라는 반응을 하고 아래처럼 지시를 합니다.

"내가 가르쳐줬던 내용은 교재의 N페이지, K페이지, M페이지를 참고해봐"

약간, 억지 예시같지만 나름 포인터가 이런 기능을 유사하게 한다를 보여드리고 싶었습니다. 이미 한번 했던 행동을 또 반복하는건 효율적이지가 않습니다.

C언어도 마찬가지죠. 한번 선언해놓고 수행한 함수를 또 반복수행하기 위해서 함수를 선언하고 또 돌리고, 또 선언하고 또 돌리고... 할 필요가 없습니다. 그냥 "몇몇 페이지를 참고해봐" 하는거처럼 함수가 가진 메모리 주소를 가리키면서 "이 함수를 수행해봐!" 하는 것이죠. 이게 포인터가 필요한 이유입니다.


코드 설명

이제 위 소스코드를 천천히 파헤쳐 봅시다.

#include <stdio.h>
int main()
{
	int a = 5;
    int *num = &a;
    printf("%d\n",a);
    printf("%p\n",&a);
    printf("%d\n",*num);
    printf("%p\n",num);
    
    return 0;
}
  • 결과값들을 보면 코드와 달리 뭔가 동일해보이긴 합니다.
    가장 쉬운 첫번째부터 봅시다.

Input : int a = 5;
Output : printf("%d\n",a); = 5

  • 무난히 이해할 수 있는 코드입니다. 변수명 a라는 상자에 변수값 5를 넣었고 이 변수는 '정수형'으로 선언되었다. 그리고 이걸 출력하면 변수명 a가 담고있는 값을 보여준다. 이거죠?

Input : int *num = &a;
Output : printf("%p\n",&a); = 주소값

Okay, '*'는 무슨 말인지? 그리고 새로운 형식 지정자가 보이는데 %p는 무슨 말인지..??

  • '*'는 산술연산자에서 곱셈으로도 쓰입니다. 다만, 곱셉의 경우는 정수 혹은 실수타입의 두 변수 사이에서 사용될 때 곱셈으로 적용되구요. 위 같은 경우는 '포인터 변수' 라고 합니다.

오우쉣... 포인터 변수라구요? 이름에 겁먹을 필요는 없습니다.

중요! 포인터라는 것은 선언된 변수가 저장된 메모리 공간이 갖고 있는 주소값을 가리키는 것입니다.

필자의 경우는 이 세상에 선언된 평범한 한국인이고, 부여받은 주소는 경기도 고양시 일산동구입니다. 그러면 제 주소를 가리키고 있는 등본은 이 세상의 '포인터' 역할을 할 것입니다.

그렇기 때문에 호출할 값은 변수값이 아닌 주소값이 되니까 &a를 쓰는 것이구요. 이 주소값에 대한 형식 지정자가 %p인 것입니다.

그러면 우리는 이제 위 코드에 대해 대략적인 이해는 잡힙니다.

  • 아하! 포인터 변수 num은 변수 a가 살고있는 주소를 가리키도록 선언되었구나!
  • 아하! 그리고 그 주소값을 출력하는 형식 지정자는 %p구나!

Code 1 : printf("%d\n",*num);
Code 2 : printf("%p\n",num); = 주소값

이제 마지막 코드들을 보겠습니다. Code 1은 포인터 변수값을 출력하고자 합니다. 주소를 출력하느냐, 변수값을 출력하느냐는 형식지정자를 보면 됩니다.

  • 포인터 변수 num이 가리키는 것은 변수a의 메모리 주소이므로, 해당 주소에서 살고 있는 '변수값'을 출력하라는 것입니다.
  • Code 2는 그럼 포인터 변수 num이 가리키고 있는 주소를 출력하라는 것이겠죠?

포인터는 배열과도 밀접한 관련이 있습니다.

  • 배열이 뭐였더라? : 변수들의 아파트!

배열의 특징 중 하나는 변수들을 연속된 메모리 공간 상에서 저장을 한다는 것입니다.

int num[5] = {0,1,2,3,4};

따라서, 배열 num의 원소들 0,1,2,3,4는 메모리 주소값의 끝부분에서 규칙을 발견할 수 있을 것입니다. 이 부분은 바로 이전 포스팅에서도 설명을 했었죠?
1차원배열에 대한 글!

이러한 특징 때문에 포인터를 통해서 배열에 접근하는 것은 굉장히 편리합니다.

해당 그림을 보면 배열을 통해 선언한 정수형 원소들을 보면 끝자리가 4씩 증가합니다. (16진수) 따라서 배열의 전체 인덱스를 알지 못해도, 최소 하나의 인덱스만 안다면 나머지 원소들이 갖는 주소값을 아는 것은 굉장히 쉽습니다.


2중 포인터

2중 포인터?

어려운 개념은 아닙니다. 이 글의 제일 위에 있는 사진을 보시면 'int **' 라는 애가 있어요.

변수의 주소 를 가리키는 포인터의 '주소' 를 가리키는 포인터 입니다.

2중 포인터도 요긴하게 쓰일 일이 많지만 오늘은 여기까지만 다루고 천천히 넓혀가는 것으로 하겠습니다.

profile
방구석백수 코드몽키

0개의 댓글