본문 바로가기

BackEnd/C

포인터의 포인터

반응형

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 = &num;  // * 연산자를 한번 사용하는 경우

**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증가시킨다.














반응형