본문 바로가기

다중 포인터

1. 포인터의 포인터

 

앞의 포인터 변수는 기본 타입(char, short, int, long, long, float, double) 변수를 가리키고 있다.

포인터의 포인터, 즉 이중 포인터(double pointer)는 기본 타입 변수가 아닌 포인터 변수를 가리키는 포인터 변수다.

 

이중 포인터 변수는 다음과 같이 선언한다.

 

int** dptr;

 

언뜻 보면 어려워 보일 수 있지만, 사실 뭔가를 가리키고 있다는 것은 변함이 없다.

다만 가리키는 대상이 포인터 변수일 뿐이다. int형 변수와 포인터 변수는 저장하는 값의 유형이 다를 뿐이지, 결국 값을 저장할 수 있는 변수라는 점은 같았다. 마찬가지로 더블 포인터와 싱글 포인터는 저장하는 값이 포인터 변수의 주소인지, 기본 타입 변수의 주소인지 다를 뿐이다.

 

다음과 같이 선언되었다고 하자.

 

int num = 5; 

int* ptr = #

int** dptr = &ptr;

 

현재 메모리의 상태는 다음과 같이 표현할 수 있다.

 

 

 

 

이 참조 관계를 식으로 정리하면 다음과 같다.

 

① ptr == &num

② dptr == &ptr

③ *ptr == num

④ **dptr == num

⑤ *dptr == ptr == &num

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
 
int main()
{
    int num = 5;
    int* ptr = &num;
    int** dptr = &ptr;
 
    printf("&num: %p\n"&num);
    printf("ptr: %p\n", ptr);
    printf("*dptr: %p\n\n"*dptr);
 
    printf("&ptr: %p\n"&ptr);
    printf("dptr: %p\n\n", dptr);
 
    printf("num: %d\n", num);
    printf("*ptr: %d\n"*ptr);
    printf("**dptr: %d\n"**dptr);
 
    return 0;
}
cs

 

 

 

 

이중 포인터 역시 싱글 포인터와 마찬가지로 가리키는 대상을 변경할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
 
int main()
{
    int num1 = 3, num2 = 5;
    int* ptr1 = &num1;
    int* ptr2 = &num2;
    int** dptr = &ptr1;
 
    printf("&num1: %p\n"&num1);
    printf("*dptr: %p\n"*dptr);
    printf("&ptr1: %p\n"&ptr1);
    printf("dptr: %p\n\n", dptr);
 
    dptr = &ptr2;
    printf("dptr = &ptr2 실행 후\n");
    printf("&num2: %p\n"&num2);
    printf("ptr2: %p\n", ptr2);
    printf("*dptr: %p\n"*dptr);
    printf("*ptr2: %d\n"*ptr2);
    printf("**dptr: %d\n"**dptr);
 
    return 0;
}
cs

 

 

13행까지의 참조 관계는 다음과 같다.

 

 

 

 

그리고 15행에 의해 참조 관계는 다음과 같이 바뀐다.

 

 

 

 

int형 변수 간의 call-by-reference는 int*형 변수로 구현했다.

그렇다면 int*형 변수 간의 call-by-reference는 어떻게 구현할까?

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
 
void swapPointer(int* ptr1, int* ptr2);
 
int main()
{
    int num1 = 3, num2 = 5;
    int *p1 = &num1, *p2 = &num2;
 
    printf("*p1: %d\n"*p1);
    printf("*p2: %d\n\n"*p2);
 
    swapPointer(p1, p2);
    printf("*p1: %d\n"*p1);
    printf("*p2: %d\n"*p2);
 
    return 0;
}
 
void swapPointer(int* ptr1, int* ptr2)
{
    int* temp = ptr1;
    ptr1 = ptr2;
    ptr2 = temp;
}
cs

 

 

 

 

결과를 보기 전에 코드에서 이상함을 느꼈다면 성공이다.

사실 바뀌지 않는 것이 당연하다.

 

 p1 과  ptr1 은 완전히 별개다.  ptr1 이라는 매개변수를 통해  p1 의 값이 복사되어

 swapPointer  함수로 전달될 뿐이니, 실제로 바뀌는 것은  ptr1 과  ptr2 의 값이다.

따라서  p1 이 가리키는 대상과  p2 가 가리키는 대상이 바뀔 리가 없는 것이다.

 

따라서 int형 변수 간의 call-by-reference는 int*형 변수로 구현한 것처럼,

int*형 변수 간의 call-by-reference는 당연히 int**형 변수로 구현해야 하는 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
 
void swapPointer(int** dptr1, int** dptr2);
 
int main()
{
    int num1 = 3, num2 = 5;
    int *p1 = &num1, *p2 = &num2;
 
    printf("*p1: %d\n"*p1);
    printf("*p2: %d\n\n"*p2);
    
    swapPointer(&p1, &p2);
    printf("*p1: %d\n"*p1);
    printf("*p2: %d\n"*p2);
 
    return 0;
}
 
void swapPointer(int** dptr1, int** dptr2)
{
    int* temp;
    
    temp = *dptr1; //temp = p1;
    *ptr1 = *dptr2; //p1 = p2;
    *ptr2 = temp; //p2 = p1;
}
cs

 

 

 

함수를 통해 값을 바꾸려면 그 함수로 주소를 전달한 후 그 주소에 있는 값을 바꿔야 하므로,

기본 타입 변수의 값을 바꾸려면 싱글 포인터로,

싱글 포인터의 값을 바꾸려면 매개변수를 더블 포인터로 선언해야 한다.

 

 

 

 

2. 삼중 포인터

 

포인터 변수의 주소값을 저장할 수 있는 변수는 이중 포인터였다.

그렇다면 삼중 포인터(triple pointer)에는 당연히 이중 포인터 변수의 주소가 저장되는 것이다.

 

삼중 포인터 변수는 다음과 같이 선언한다.

 

int*** tptr;

 

사실 이중 포인터만 제대로 알고 있다면 삼중이 아니라 오중 포인터라도 어려울 게 없다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
 
int main()
{
    int num = 3;
    int* ptr = &num;
    int** dptr = &ptr;
    int*** tptr = &dptr;
 
    printf("num: %d\n", num);
    printf("*ptr: %d\n"*ptr);
    printf("**dptr: %d\n"**dptr);
    printf("***tptr: %d\n\n"***tptr);
 
    printf("&num: %p\n"&num);
    printf("ptr: %p\n", ptr);
    printf("*dptr: %p\n"*dptr);
    printf("**tptr: %p\n\n"**tptr);
 
    printf("&ptr: %p\n"&ptr);
    printf("dptr: %p\n", dptr);
    printf("*tptr: %p\n\n"*tptr);
 
    printf("&dptr: %p\n"&dptr);
    printf("ptr: %p\n", tptr);
 
    return 0;
}
cs

 

 

 

참조 관계는 다음과 같다.

 

 

 

다중 포인터에서 참조 관계가 헷갈린다면 다음을 기억하자.

 

& 연산과 * 연산은 서로 상쇄된다

 

예를 들어  **tptr 은 다음과 같은 과정에 의해  ptr 임을 알 수 있다.

**tptr == **(&dptr) == *dptr == *(&ptr) == ptr

 

 

'Programming > C' 카테고리의 다른 글

2차원 배열과 포인터  (0) 2019.04.09
다차원 배열  (0) 2019.04.01
매개변수  (0) 2019.03.24
포인터와 배열의 관계  (0) 2019.03.17
포인터  (0) 2019.03.16