이중포인터에 앞서 필요한 개념을 간단히 설명하겠다. 변수는 메모리상에 데이터가 차지하는 공간을 대변한다. 이런 변수는 시작주소값이 존재하고 타입이 존재한다. 주소값과 타입을 알면 메모리 공간에서 변수를 해석할 수 있다. 이렇게 기본적인 지침을 설명하는 곳은 그리 흔치 않다.

 

포인터 타입의 행동특성

포인터의 개념은 실제로 너무도 단순 명확하다. 변수의 주소를 가리키는 또 다른 변수라 생각하면된다. 그래서 포인터라고도 하지만 포인터 '변수'라고도 불리운다. 주소를 가리킨다는 말은 실제로는 포인터는 대상체의 주소값을 지닌다는 말이다. 포인터의 동작은 이렇게 자신이 지닌 값, 즉 주소값을 '*'연산을 통해서 참조하는 특징을 한다. 즉 포인터 타입의 행동특성이다.

 


이중 포인터란

그럼 포인터도 일종의 변수기 때문에, 포인터를 가리키는 포인터도 존재한다. 이를 이중 포인터라고 한다.

그런데 이런 이중 포인터의 선언 타입은 첫번째 포인터의 선언 타입을 따라간다. 결국 이중포인터도 최초의 변수 즉 최종 대상체가 되는 값의 타입을 기준으로 선언 되는 것이다. 왜냐면 포인터 자신의 타입은 포인터 타입(4byte)만 존재하기 때문에 자신의 타입 자체에 대해서는 신경 쓸 필요가 없기 때문이다.

 

위에 나온내용을 정확히 이해한다면 3중 4중 포인터도 같은 방식으로 이해하고 활용하면 된다.

 

이중 포인터의 선언 방법과 메모리 구조

이중포인터의 선언은 단순히 '*'을 한번 더 붙여 주면 된다.(이전 포인터에 대한 이해에서도 말했다 시피 선언시 '*'은 연산자가아니다.)

 

위 코드는 포인터와 이중포인터가 어떻게 동작하는지 간략하게 알려준다.

위 코드를 메모리 상에서 나타내보면 다음과 같다.

 

이중포인터

p2가 지닌 값은 p1의 주소이므로 포인터의 동작틍성에따라 '*'연산을 통해 자신이 지닌 값을 주소의 시작점으로 하는 p1을 참조한다. '*'연산을 통해 p1이 지닌값, 즉 a의 주소값을 알 수 있다. 같은 방식으로 **을 하면 p1이 지닌 a의 주소값을 참조하여 a의 값을 알 수 있다.



&연산자의 활용시 주의

반대의 경우 &를 통해서 자신의 주소값을 알 수 있지만, &&를 사용하지는 못한다. 이유는 &연산의 결과 값은 상수기 때문이다.

상수는 메모리의 공간을 나타내는 변수가 아니고, 단순히 값 그자체이기 때문에 C언어상에서는 위 그림과같은 위치적인 표현을 할 수 없기 때문이다. 이와 비슷한 예롤 캐스팅연산의 예를 들 수 있다. 캐스팅연산을 하면 그 연산을 한 수식내에선 캐스팅후의 값은 상수가 된다. 즉 캐스팅 연산자는 캐스팅을 하는 대상의 타입을 완전히 바꾸는 것이 아니고 그 수식내에서만 대상체의 타입을 바꾼 상수를 반환하는 형태다.



# 더블 포인터! 제대로 알고 써먹기!

더블포인터의 개념을 적당히 알고 있나요?! 흔히 이중포인터라 불리는 개념을 그리 많이 사용해보지 못하던 찰나에,실제로 문제에 봉착하여 이렇게 포스팅을 해 봅니다. 많은 도움되길 바랍니다!

더블포인터(double pointer)란?
 > 말 그대로 포인터가 이중으로 사용된 경우를 말한다. 싱글포인터 주소값을 가르키기 위해 사용된다.


이런식으로 "싱글포인터를 가리키는 포인터가 더블포인터다 !" 라고 말씀 드릴수 있겠습니다! 
그렇다면 why?! 더블 포인터라는 개념이 필요한건지 궁금해 하실 겁니다.

 

1
2
3
4
5
6
7
8
9
10
void func(char* _ptr){
     _ptr = (char*)1;
}
int main()
{
    char* ptr = NULL;
    printf("before call is %x\n", ptr);
    func(ptr);  printf("after call is %x\n", ptr);
    return 0;
}

위 코드의 결과 값은 0, 0 입니다. call by value & reference 이라고 하지엔 주소값을 넘겨주어,, 뭔가 모호합니다.그렇다면 stack 메모리 구조로 해색해 봄으로써 해당 문제를 해결해 보도록 하겠습니다.(아래 그림에 0x0002 주소의 변수명은 _ptr입니다)

(정정합니다! 아래 보시는 메모리 스샷의 경우 포인터 또는 정수 값으로 할당시, 주소에 있어서 1씩 변화를 보이는데,, 이는 잘못된 표기로써 ,, 정수의 메모리 할당크기는 운영체제의 시스템(32, 64bit ..etc)체계에 따라 다르겠지만 정수는 4byte, 포인터변수는 4byte이므로 이를 인식하셔서 그림에 혼란 없으시길 바랍니다..예를 들어 바로 하단의 변수 ptr 포인터 변수의 경우 0x0001번째부터 할당되었으므로 다음 파라미터로 선언된 ptr은 0x0005번지 부터 할당되겠지요? 다음부턴 잘하겠습니다 ㅠㅠ) 



1
2
3
4
5
6
7
8
9
  
int main()
{   char* ptr = NULL; // ptr변수를 메모리에 올리고 NULL 값으로 체워준후
    printf("before call is %x\n", ptr); // 출력을 하면 0이 출력됩니다.
        func(ptr); // 함수가 호출되고 아래와 같은 출력을 보입니다.<br>
        /* 함수가 종료되고 _ptr 값은 스택에서 지워집니다 */
    printf("after call is %x\n", ptr); // 출력값에 변화가 없습니다.
    return 0;

1
2
3
4
5
6
  
void func(char* ptr)
{
     ptr = (char*)1;  // ptr에 값을 할당해도 main함수의 ptr에는
                    // 변동이 없다.(위의 그림을 보면 확인할수 있다.)

즉 포인터를 조작할수 있는 무엇인가를 필요로 하게 되는데 그것이 바로 더블 포인터다!아래와 같은 방법으로 함수 밖의 포인터를 조작할수 있다.

 



1
2
3
4
5
6
7
8
9
10
void func(char** _ptr) // _ptr파라미터의 경우 포인터의 주소를
{                               // 받으므로 더블포인터로 정의한다
     *_ptr = (char*)1;  // _ptr이 가르키고 있는 주소의 값을 변경한다
}
int main()
{   char* ptr = NULL;
    printf("before call is %x\n", ptr); // 0출력
    func(&ptr); // 포인터의 주소값을 넘겨준다.
    printf("after call is %x\n", ptr); // 포인터 조작으로 1출력  return 0;
}
결과 값은 0,1이 출력된다! 이와같이 함수 외부의 포인터 값을 함수 내부에서 조작하기 위해 더블 포인터를 사용한다.


블로그 이미지

잉비니

,