before 2020/C

이중포인터

hom2s 2009. 6. 24. 01:11
아래의 질문은 지식인에 올라온 본인이 답변한 질문으로 이중포인터의 개념을 다시 기억하기 위해 블로그로 옮겨 왔습니다.

<질문>
char *c[]={"ENTER","COLD","WIN","ANALYSIS"};
char **cp[]={c+3,c+2,c+1,c};
char ***cpp=cp;

void main(){
      printf("%s ",**++cpp);
      printf("%s ",*--*++cpp+2);
      printf("%s ",*cpp[-2]+6);
      printf("%s\n",cpp[-1][-1]);
}

이중포인터자체도 이해가 안대고
이문제 자체도 이해가 안대네요;;
자세한 설명분 부탁드립니다..
내공 팍팍검;;

※adk0024님의 질문

<답변>

이중포인터란 포인터를 가리키는 포인터입니다.

그냥 포인터는 아시다시피 어떤 변수의 값이 저장되어있는 곳의 주소를 가리키는 변수입니다.

근데 값을 가리키는 변수(즉,포인터) 또한 주소를 가지고 있습니다. 이것을 가리키는것이 이중 포인터이지요.

 

질문자님이 어느정도 알고 계신지 모르겠지만.. 포인터를 처음 공부하시는 분들에게도 도움이되고자

굉장히 차근차근 설명해 보겠습니다.

 

예를들어,

        int a = 50;

이라고 한다면

이렇게 될겁니다. a라는 이름이 달린 공간안에 50이 들어가는거죠.

하지만 이 공간은 편의상 a라고 불렀을뿐 사실 메모리상에서 사용되는 고유의 주소를 가지고 있습니다.

만약 그 공간이 A001이라는 주소의 공간이라면 대충 저런 공간에 50이 들어간겁니다.

포인터란 이 주소값을 가지고 있는 변수이죠.

 

       int *p_a = &a;

라고 한다면

이런 모습이 될겁니다. 왼쪽 공간이 p_a라는 공간이고 A001이라는 주소값을 가집니다.

p_a 역시 변수입니다. 변수이긴 변순데 다른변수의 주소값을 가져 포인터변수라 하죠. 

근데 p_a란 포인터변수도 결국 변수이다 보니 자신의 주소을 가지죠. 바로 PK0101이란 주소입니다.

이중포인터란 이 포인터변수의 주소값을 가지는 놈입니다.

 

       int **pp_a = &p_a;

이라고 한다면

이런 모습니 될겁니다. pp_a또한 자신의 주소를 가지죠. 누군가 pp_a의 주소값을 가진다면 삼중포인터변수가 되는것입니다.

 

이중포인터란게 이런겁니다. 이제 문제를 보죠.

       char *c[]={"ENTER","COLD","WIN","ANALYSIS"};
우선 이코드 입니다. 배열은 배열인데 char * 가 붙어있는 걸로 봐선 char형 포인터변수의 배열이군요.

그림을 그리자면..

이렇게 되겠네요. 위의 숫자는 주소를 표현한게 아니고 배열의 인덱스를 표현한겁니다.

 

       char **cp[]={c+3,c+2,c+1,c};
이코드 부터 이중포인터네요. 배열은 배열인데 char ** 가 붙어있는 걸로 봐서 char *형 포인터 변수입니다.

한마디로 주소값을 가지고 있는 포인터 변수들의 주소를 값으로 가지고 있는 배열입니다.(;;)

하지만 cp에 대입한 값을 보니 c의 순서로 넣진 않았네요. c+3이 먼저왔고 2,1,0순서로 들어갔습니다.

배열은 '배열이름+숫자'로 접근 가능하다는건 아시리라 생각합니다.

마지막으로 char ***cpp=cp; 코드를 더해서 종합적으로 그리자면..

결국 이정도 그림이 되겠네요.

CP란 배열안에 A00101 이라던지 OD02039 이라던지 하는 주소값이 들어있겠죠.

 

이제 문제를 보자면..

  printf("%s ",**++cpp);

우선 이놈입니다.

그림을 보면 cpp는 cp의 처음 요소의 주소값을 가지고 있습니다.

(배열의 이름은 그배열의 첫요소의 주소값을 가지고 있습니다. 따라서 cpp가 cp의 첫요소를 가리키고 있다고 볼수있는거죠. 위에 ***cpp=cp 이렇게 했잖아요.) 

그리고 cp의 처음 요소는 c의 3번요소의 주소값을 가지고 있네요.

그럼 **++cpp는 **를 사용하여 포인터변수의 값에 접근하되 cpp를 ++ 하였기에.

cpp가 cp의 첫요소(0번)를 가리키고 있는데 이를 ++하면 두번째요소. 즉 cp의 1번을 가리키게 됩니다.

cp의 1번은 c의 2번요소이죠? 그래서 printf 함수를 찍으면 WIN 이라고 출력이 됩니다.


  printf("%s ",*--*++cpp+2);
두번째 문제네요. 우선 현재 cpp는 cp의 2번째 요소. 즉 cp 1번을 가리키고 있습니다.

거기서 ++를 했군요. (연산자 우선순위에 보면 ++,--등의 연산자는 오른쪽에 있는걸 먼저 계산합니다.)

그럼 이제 cp의 3번째 요소를 가리키겠네요. cp 2번입니다. 그건 c의 1번이겠죠?

하지만 --가 또 붙었군요.

**++cpp 이건 cpp가 가리키던 cp에서 1칸 뒤에것을 가리킨다는 말이고

*++*cpp는 cp가 가리키던 c에서 1칸뒤에것을 가리킨다는 의미입니다.

다른거죠. --는 두번째 경우에 해당하기 때문에 cp 2번은 c의 1번을 가리켰다가 이젠 c의 0번을 가리키게 됩니다. ENTER 이네요. 근데 여기서 +2가 있네요.

*--*++cpp는 어렵게 보이지만 결국 **cpp 이것처럼 포인터변수의 값을 뜻합니다. 거기서 +2를했으니

지금 가리키고 있는 ENTER에서 두칸 뒤로가서 시작하란 말이죠. T부터 출력을 합니다. 결국 TER이 출력되죠.

 

  printf("%s ",*cpp[-2]+6);
이제 배열과 함께 사용되네요. 원래 이중 포인터는 이차원배열처럼 사용가능합니다. 같이 섞어서도 사용하죠.

*cpp[-2]란 *cpp에서 cp를 뜻한다는 것을 알수있고 [-2]에서 지금 cp의 위치에서 두칸뒤에것을 말한다는 것을 알 수 있습니다. 지금 cp의 위치가 어디었죠? cp의 2번이었군요. c의 0을 가리키고 있는 놈입니다.

cp의 2번에서 뒤로 두칸이면 cp 0번입니다. c의 3번을 가리키고 ANALYSIS라는 값이군요.

근데 +6이 되어있기에 6칸 이후부터 접근하란 뜻으로 해석하고 IS만 표시하게 됩니다.

 

  printf("%s\n",cpp[-1][-1]);

지금까지 연산으로 cpp -> cp 2 -> c 0 이라는 위치를 가지고 있습니다.

윗 문제의 [-2]는 현재 위치에서 앞으로 두칸에 접근하라는 것이지 --,++처럼 대입의 과정이 없기에

지금의 위치는 윗윗문제가 끝난 시점의 위치와 동일합니다.

cpp의 행은 cp의 위치를 뜻하고 열은 c의 위치를 나타냅니다. (규칙이니까 외워야 합니다.;; = cpp[행][열])

cpp[-1]로 cp의 위치에서 한칸 앞에것에 접근하게 됩니다. cp 1번이네요 c의 2번입니다.

하지만 열인 [-1]이 더있군요. c의 1번으로 이동합니다. COLD입니다.

 

결국 결과 값은 WIN TER IS COLD 입니다.

이제 막 배우기 시작하신분들을 위해 굉장히 자세히 쓴다고 쓰다보니 너무 길게썼네요;;;

사실 쓰다가 그냥 '알겠지'하고 넘어간 부분도 몇군데 있습니다.(;;전부설명하기 힘들어서;;)

그리고 단어선택에 약간의 미스가 있을수도 있겠네요. 하지만 전체적인 개념설명엔 틀린것이 없을듯합니다.

이문제는 포인터와 배열간의 관계와 연산에 대한 문제입니다. 제글도 읽어보고 스스로 공부도 해보시면

많은 도움이 되겠네요.


'before 2020 > C' 카테고리의 다른 글

포인터의 Call by Value  (2) 2009.06.24