보통 그냥 포인터라고 하면 포인터를 선언할 당시에 *연산자가 하나만 쓰입니다.
선언할 때 *연산자를 더 늘려서 이중, 삼중까지 가능합니다.
영어로는 더블 포인터,트리플 포인터라고 부릅니다.

이중 포인터

이중 포인터는 그나마 쓰이지만 삼중 포인터는 잘 안 쓰입니다.
이중 포인터는 2차원 배열이나 포인터 그자체를 다뤄야 할 때 많이 쓰입니다.

 

이중 포인터 선언

Type ** Name;

*연산자 1개 더 붙여주면 됩니다.

 

이중 포인터에 대한 이해

이중 포인터를 이해하려면 단일 포인터와 *연산자를 빠삭하게 이해하고 있어야 합니다.

#include <stdio.h>
int main(void) {
       int num = 10;
       int * ptr = &num;
       int ** dptr = &ptr;
}

이중 포인터 그림

하나씩 어떠한 값을 가지고 있는지 알아봅시다.
이때
ptr의 주소값 004FFE7C
num의 주소값을 008FF9A4 라고 합시다.

의미(가지고 있는 값)
dptr 포인터 변수 ptr의 주소값 (004FFE7C)
*dptr 포인터 변수 ptr가 가지고 있는 값 (008FF9A4)
**dptr 포인터 변수 ptr가 지시하고 있는 값 (10)

아래는 예제입니다.

#include <stdio.h>
int main(void) {
       int num = 10;
       int * ptr = &num;
       int ** dptr = &ptr;
       printf("num의 주소값:%p num의 값:%d \n", &num, num);
       printf("ptr의 주소값:%p , ptr가 지시하고 있는 값:%d , ptr가 가지고 있는 값:%p  \n", &ptr, *ptr,ptr);
       printf("dptr의 주소값:%p , dptr가 지시하고 있는 값:%p , dptr가 가지고 있는  값:%p \n", &dptr, *dptr, dptr);
       printf("dptr가 가지고 있는 값:%p *dptr가 가지고 있는 값:%p , **ptr가 가지고  있는 값:%d", dptr, *dptr, **dptr);
}

해당 출력 결과는 아래와 같습니다.

num의 주소값:010FFA38 num의 값:10
ptr의 주소값:010FFA2C , ptr가 지시하고 있는 값:10 , ptr가 가지고 있는 값:010FFA38
dptr의 주소값:010FFA20 , dptr가 지시하고 있는 값:010FFA38 , dptr가 가지고 있는 값:010FFA2C
dptr가 가지고 있는 값:010FFA2C *dptr가 가지고 있는 값:010FFA38 , **ptr가 가지고 있는 값:10

그래서 어디에 쓰이는가?

아래는 2차원 배열에 대한 예제입니다.

#include <stdio.h>
void Print2D(int ** ptr) {
       for (int i = 0; i < 3; i++) {
              int * ptr_temp = (ptr+i*3); //가로길이가 3이라서 다음 [i+1][0]배열에  접근할려면 *3해줘야됨
              for (int j = 0; j < 3; j++) {
                     printf("%d \n",*ptr_temp+j);
              }
       }
}
int main(void) {
       int arr[3][3] = {
              {1,2,3},
              {4,5,6},
              {7,8,9}
       };
       Print2D(arr);
       
}

근데 이렇게 사용하는건 매우 좋지 않다고 생각합니다.

[] 연산자를 사용하여 접근하는 게 보기도 좋고 이해하기도 훨씬 쉽습니다.

파라미터 부분에서도 **보다는 [3][]라고 써주며 "2차원 배열을 인자로 받을 거야"라고 알려주는 게 좋습니다.

 

아래 예제는 포인터에 대한 예제입니다.

#include <stdio.h>
#include <stdlib.h>
void MemoryAlloc(int ** ptr) {
       *ptr = malloc(sizeof(int));
       **ptr = 100;
}
int main(void) {
       int num = 10;
       int * ptr = &num;
       printf("ptr 가지고 있는 값:%p ptr 지시하고 있는 값:%d \n", ptr, *ptr);
       MemoryAlloc(&ptr);
       printf("ptr 가지고 있는 값:%p ptr 지시하고 있는 값:%d \n", ptr, *ptr);
       free(ptr);
       
}

사용자 정의 함수에서 포인터 자체를 다뤄야 할 경우에 쓰입니다.

이걸 보고 계신분이라면 동적 할당을 잘 모르시는 분이 대다수 일 겁니다.

위의 예제는 런타임 도중에 변수 하나를 더 만들어서 ptr가 지시하는 변수를 바꿔버립니다.

ptr 가지고 있는 값:00EFFDDC ptr 지시하고 있는 값:10
ptr 가지고 있는 값:000A9DE0 ptr 지시하고 있는 값:100

출력 결과

 

2차원 배열의 이름 특성과 주의사항

배열 포인터와 포인터 배열을 혼동하면 안 됩니다.

int * WhoA [4]; //포인터 배열
int (*whoB) [4]; //배열 포인터 

포인터 배열은 포인터 변수로 이루어진 배열이고

배열 포인터는 배열을 가리킬 수 있는 포인터 변수입니다.

 

2차원 배열을 함수의 인자로 전달하려면 두 가지 방법이 있습니다.

void SimpleFunc(int (*parr1)[7]){...}
void SImpleFunc(int parr1[]){...}

 

'프로그래밍 > C' 카테고리의 다른 글

C언어 함수 포인터와 void 포인터  (0) 2019.04.18
포인터의 포인터(이중 포인터)에 대한 이해  (0) 2019.04.18
C언어 다차원 배열  (0) 2019.04.18
상수 형태의 문자열을 가리키는 포인터  (0) 2019.04.17
포인터 연산  (0) 2019.04.17
C언어 포인터  (0) 2019.04.17

댓글을 달아 주세요