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 = #
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 = #
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 |