1. 포인터 변수도 변수니 당연히 주소값을 얻을 수 있다.
포인터 변수는 선언시 메모리 영역에 4바이트의 메모리 공간 할당이 이루어진다.
때문에 포인터 변수에 대한 주소 값도 당연히 존재한다.
주소값은 & 연산자를 똑같이 사용하면 얻는다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> int main(void) { int num1=3; double num2=3.15; int * ptr1=&num1; double * ptr2=&num2; printf("ptr1의 저장 값: %#x \n", ptr1); printf("ptr1의 주소 값: %#x \n\n", &ptr1); printf("ptr2의 저장 값: %#x \n", ptr2); printf("ptr2의 주소 값: %#x \n\n", &ptr2); return 0; } | cs |
1 2 3 4 5 | ptr1의 저장 값: 0x62fe4c ptr1의 주소 값: 0x62fe38 ptr2의 저장 값: 0x62fe40 ptr2의 주소 값: 0x62fe30 | cs |
12행을 보면 &연산자를 이용해 ptr1이라는 포인터변수의 주소값을 구하고 있다.
그런데 이렇게 &연산자를 통해서 얻는 것은 단순히 주소 값이 아니라 상수 형태의 포인터이다.
그렇다면 12행, 15행에서 반환되는 포인터의 형은 무엇일까? 답을 먼저 말하면 int ** 이다.
2. 포인터 변수의 주소값 저장
위 예제의 12행과 15행에서 반환되는 포인터 변수의 주소 값을 포인터 변수에 저장해보자
포인터 변수 선언시 중간에 * 를 추가한다는 기본규칙도 기억하자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <stdio.h> int main(void) { int num1=3; double num2=3.15; int * ptr1=&num1; double * ptr2=&num2; int** dptr1=&ptr1; double** dptr2=&ptr2; printf("ptr1의 저장 값: %#x \n", ptr1); printf("ptr1의 주소 값: %#x \n\n", dptr1); printf("ptr2의 저장 값: %#x \n", ptr2); printf("ptr2의 주소 값: %#x \n\n", dptr2); return 0; } | cs |
1 2 3 4 5 | ptr1의 저장 값: 0x62fe4c ptr1의 주소 값: 0x62fe38 ptr2의 저장 값: 0x62fe40 ptr2의 주소 값: 0x62fe30 | cs |
11행에서 포인터 형이 int*인 변수의 주소 값은 포인터 형이 int**인 변수에 저장해야 함을 보여준
다. 그리고 위 예제의 메모리 참조 관계를 그림으로 정리했다.
3. 포인터의 포인터를 이용한 올바른 *연산(이중 포인터의 연산)
다음 두 포인터 선언을 보자
int* ptr;
int** dptr;
포인터 ptr은 int형 포인터이다. 따라서 ptr에 저장되는 값은 int형 변수의 주소값이다.
따라서 포인터 ptr에 허용이되는 ,참조를 위한 * 연산은 다음과 같다.
*ptr = 100;
반면 dptr은 int형 포인터의 포인터이다. 따라서 dptr에 int형 포인터의 주소값이 저장된다.
즉 dptr에 값이 저장되면 다음과 같은 메모리 구조가 형성될것이다.
따라서 dptr에 허용되는 포인터 연산은 다음 두가지다.
int num =0;
*dptr = # // * 연산자를 한번 사용하는 경우
**dptr = 100; //* 연산자를 두번 사용하는 경우
즉 포인터 dptr을 이용해서 참조할 수 있는 대상이 2개인 것이다.
* 연산자를 한번만 사용하면 dptr이 가리키는 또 다른 포인터를 의미하고,
* 연산자를 두번 사용하면 dptr이 가리키는 포인터가 가리키는 변수를 의미하게 된다.
이 관계를 그림으로 봐보자
포인터 연산의 의미를 확인하기 위한 예제를 봐보자
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 | #include <stdio.h> int main(void) { int num1=3; int num2=30; int* ptr=&num1; int** dptr=&ptr; printf("ptr이 가리키는 변수 값: %d \n", num1); printf("ptr이 가리키는 변수 값: %d \n", *ptr); printf("ptr이 가리키는 변수 값: %d \n\n", **dptr); *dptr=&num2; // ptr=&num2와 동일 printf("ptr이 가리키는 변수 값: %d \n", num2); printf("ptr이 가리키는 변수 값: %d \n", *ptr); printf("ptr이 가리키는 변수 값: %d \n\n", **dptr); **dptr+=3000; printf("ptr이 가리키는 변수 값: %d \n", num2); printf("ptr이 가리키는 변수 값: %d \n", *ptr); printf("ptr이 가리키는 변수 값: %d \n\n", **dptr); return 0; } | cs |
1 2 3 4 5 6 7 8 9 10 11 | ptr이 가리키는 변수 값: 3 ptr이 가리키는 변수 값: 3 ptr이 가리키는 변수 값: 3 ptr이 가리키는 변수 값: 30 ptr이 가리키는 변수 값: 30 ptr이 가리키는 변수 값: 30 ptr이 가리키는 변수 값: 3030 ptr이 가리키는 변수 값: 3030 ptr이 가리키는 변수 값: 3030 | cs |
15행에서 현재 dptr이 ptr을 가리키므로 *dptr은 ptr과 동일하다. 따라서 이 문자에 의해서 포인터
ptr이 가리키는 대상은 num2로 변경된다.
20행에서는 **dptr은 num2를 가리키게 된다. 그러므로 num2의 값을 3000증가시킨다.
'BackEnd > C' 카테고리의 다른 글
제한된 형태의 포인터 연산 (0) | 2019.03.13 |
---|---|
포인터 배열 (0) | 2019.03.13 |
문자열 배열과 문자열을 참조하는 포인터 (0) | 2019.03.12 |
&연산자가 반환하는것은? (0) | 2019.03.12 |
잘못된 포인터 사용의 예와 NULL 포인터 (0) | 2019.03.12 |