보통 그냥 포인터라고 하면 포인터를 선언할 당시에 *연산자가 하나만 쓰입니다.
선언할 때 *연산자를 더 늘려서 이중, 삼중까지 가능합니다.
영어로는 더블 포인터,트리플 포인터라고 부릅니다.
이중 포인터
이중 포인터는 그나마 쓰이지만 삼중 포인터는 잘 안 쓰입니다.
이중 포인터는 2차원 배열이나 포인터 그자체를 다뤄야 할 때 많이 쓰입니다.
이중 포인터 선언
Type ** Name;
*연산자 1개 더 붙여주면 됩니다.
이중 포인터에 대한 이해
이중 포인터를 이해하려면 단일 포인터와 *연산자를 빠삭하게 이해하고 있어야 합니다.
#include <stdio.h>
int main(void) {
int num = 10;
int * ptr = #
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 = #
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 = #
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[]){...}
댓글