본문 바로가기

정리/구현

예제로 이해하는 함수 포인터

728x90

예제로 이해하는 함수 포인터

#1 2015.11.06. 작성

#2 2018.05.20 .수정


ex) 


#main.c


char x()

{

return 'X';

}

char y()

{

return 'Y';

}


char (*x1)();


char (*x2[2])();


char (*(*x3))();



위에서 x(), y() 함수는 정의되어 있습니다. 그러나 x1, x2, x3는 정의되어 있지 않습니다. 왜냐? 바로 함수를 가리키는 포인터이기 때문입니다.

그러나 함수 비슷한 형태를 가지고 있습니다. x1을 보면  char  (*x1)  (); 이렇게 되어있는데 이것을 두가지로 분류해서 설명해보겠습니다.


예 : char (*x1)( );


(1) char  (*x1)  ( );

우선 char를 봤을 때 return 형 또는 type이 char이다! 라는 것입니다.

계속 설명하겠습니다.


(2) char  (*x1)  ( );

이 선언에서 나오는 x1의 변수는 포인터라는 사실입니다. (1)과 합쳐서 생각하면 이 x1이 가리키는 값은 char 형이거나 return이 char 형인 것이 되겠습니다.



(3) char  (*x1)  ( );

 중요한 부분입니다. 전체 선언은 함수와 관련된어 있음을 말합니다. 따라서 (1)의 char는 return 형을 말하는 것이 되고요,

(2)의 x1은 char 형 리턴형 함수를 가리키는 포인터가 되는 것입니다.



이런식으로 설명을 해보면


예 : char (*x2[2])( ); 


배열 x2는 결국 함수를 가리키는 함수 포인터이며 각각의 함수의 return은 char 형이됩니다.



예 : char (*(*x3))( );


이 예를 해석해보면, x3는 함수를 가리키는 함수 포인터를 가리키는 포인터가 됩니다. 이때 관련 함수는 char 형을 반환하는 함수이고요.



결과 값을 출력해보기 위해 다음과 같이 적습니다.

x1=&x;  //x1=x; 도 마찬가지

x2[0]=x, x2[1]=y;

x3=&x1;  //반드시 x3 = &x1 으로 해야합니다. & 빼면 segment fault 뜹니다.



x() , x1() , x2[0](), x2[1](),  (*x3)(), (**x3)()  값을 출력해보면 각각은 다음과 같이 나옵니다.


X, X , X , Y, X, X


특히 (***x3)() 이렇게 해도 X 값이 나오고 계속 *를 늘려도 X가 나옵니다.

왜냐하면 x는 함수로 x의 주소는 함수의 주소이고 x의 value도 주소값과 동일하기 때문입니다. 즉 타고가봐야 계속 x만 나오는 겁니다.


참고로 간접지정 연산(*) 의 결합 방향은 <- 입니다. 따라서 int * a 라고 하면 (int *) a 가 되는 것입니다.

그리고 []는 * 보다 상위 순위의 연산이며 결합 방향은 -> 입니다.


이보다 더 복잡한 함수 포인터 예제는 많습니다. 아래를 보시죠.



char **argv

argv: pointer to pointer to char

int (*daytab)[13]

daytab: pointer to array[13] of int

int *daytab[13]

daytab: array[13] of pointer to int

void *comp()

comp: function returning pointer to void

void (*comp)()

comp: pointer to function returning void

char (*(*x())[])()

x: function returning pointer to array[] of pointer to function returning char

char (*(*x[3])())[5]

x: array[3] of pointer to function returning pointer to array[5] of char


DENNIS M.RITCHIE , < C PROGRAMMING LANGUAGE >



이중 char (*(*x())[])() 이 것을 분석하겠습니다.

우선 이것은 함수에 대한 선언입니다. 왜냐하면 가장 안쪽 () 를 보면 *x() 인 것을 확인 할 수 있습니다. 이것은 *(x())을 의미합니다.  결국, 해당 선언문은 type function name () { } 이런 꼴을 말하게 되고요. 나머지는 함수 가 가리키는 대상들의 특징을 담고 있습니다. { }를 입력하여 그 안에 함수에 정의할 내용을 넣어야 합니다. 일단 정의 형태를 모르니 패스하고 다음을 확인합니다.


 *x() 를 봅시다. 함수 x의 반환 값이 주소를 담는다는 의미입니다. 그러니 x함수는 반환형이 결국 주소가 되겠습니다.  

 { return 함수포인터;  } 라고 합시다. 


최종적으로 어떤 꼴의 함수의 주소를 담을 것인가 하는 것은  (*(   )[]) () 이 형태가 말해줍니다. 

 (*(A)[]) ()  이렇게 A를 넣어 설명을 해보면,

A-> 대상[0] -> function    그러니까 A는 대상[0]을 가리키고 이 대상 [0]에는 function이 담겨있는 것입니다.

 [1]

 [2]

....


이 값을 확인하기 위해선, 

printf( " %c " , (*(x()))[0]());  이렇게 확인해봐야 합니다.

물론 이를 확인하기 위해선 함수포인터 정의 + 배열로된 함수 포인터 정의  그리고 z의 반환을 함수 포인터로 정의해야 실행이 가능합니다.

테스트 해봤는데 기대했던 값은 나오고 error는 아니지만 warning이 나옵니다. int가 아니라 그런거 같은데 분석은 추후에 하도록 하겠습니다.

괴기한 예제였지만 개념을 확인하기엔 나름 의미가 있는거 같습니다. 정말로 좋은 예제인지는 현업에 가봐야 확인 할 수 있겠죠?

끄읕!

읽어주셔서 감사합니다.