[ C 언어 스터디 ]

자료출처 : 핵심 길잡이 C 프로그래밍 언어
도서출판 : 성안당


10. 포인터 ( Pointers )

 

★ 포인터의 개념 ★

포인터 ( pointer )는 데이터가 기억되어 있는 기억 장소의 주소( address )를 기호 형태
로 나타낸 것을 의미한다. 그러므로 기억된 데이터의 값을 참조하기 위해서는 변수를
사용하여 직접 참조할 수도 있고 포인터를 통하여 간접 찹조할 수도 있다.

포인터는 C 언어의 가장 대표적인 특징 중의 하나로 컴퓨터의 메모리를 간결하고
효율성 있게 제어하는 기능을 지니고 있다. 다음과 같은 경우에 주로 포인터를 사용
한다,

① 함수로부터 2개 이상의 값을 되돌려 줄 때
② 주소에 의한 호출 ( call by reference ) 방식의 경우
③ 한 함수에서 다른 함수로 편리하게 배열이나 문자열을 전달하고자 할 때
④ 링크드 리스트 ( linked list )나 이진 트리 ( binary tree )또는 하나의 데이터 구조
( data structure )가 다른 데이터 구조를 참조할 때 등과 같이 복잡한 데이터 구
조를 만들 때

주소 연산자 &는 변수의 주소를 나타낼 때 사용한다. 단순 변수, 배열 요소, 포인터
변수, 구조체 요소 앞에 붙어서 그들이 기억된 기억 장소의 위치, 즉 주소를 나타낸다.
예를 들어, num이 변수명이라면 &num는 변수 num의 주소를 의미한다.

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int x ;
x=100 ;
printf ( " x = %d \n &x = %u \n " , x , &x ) ;

}
▶ 실행 결과
x = 100
&x = 50120


단, 변수 x의 주소는 시스템에 따라 달라질 수 있다.

이때 주소는 16진형( %x )이나 unsigned형( %u )으로 출력하면 된다. 간접 연산자 ( * )
는 포인터 변수 앞에 붙어서 그 포인터 변수가 가리키는 주소에 기억되어 있는 내용을
나타낸다. 예를 들면, 변수 num에 대하여

num == * ( &num ) ;

이 가능하다. 이것은 변수 num의 주소에 기억되어 있는 값을 의미한다.  


★ 포인터 변수의 선언 ★

포인터 변수는 주소를 기억하는 변수이며 일반 선언 형식은 다음과 같다.

형 식
데이터형 * 포인터변수명 ;

포인터 변수명은 일반 변수명을 정하는 규칙이 동일하게 적용된다. 그리고, 포인터
변수에는 반드시 데이터형을 지정하여야 한다. 왜냐하면, 포인터 변수가 가리키는 주소
에 어떤 형태의 데이터가 기억되어 있는지 프로그램이 알아야 하기 때문이다.

즉, 데이터는 그 형에 따라 길이가 달라지기 때문에 포인터가 가리키는 주소에서부
터 몇 바이트 ( byte )까지가 원하는 데이터 값인지를 알고 있어야 한다.

메모리 주소 100 101 102 103 104 105 106 107
  Byte Byte Byte Byte Byte Byte Byte Byte
기억된 값 'A' '212' 'O.25 x 10ⁿ'  
변수명 ch num data  
  *ptr1 *ptr2 *ptr3  
  100
ptr1
101
ptr2
103
ptr3
 


다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int *a ;
float *b ;
char *c ;

printf ( " 포인터의 변수 a의 크기 = %d Byte \n " , sizeof ( a ) ) ;
printf ( " 포인터의 변수 a의 크기 = %d Byte \n " , sizeof ( b ) ) ;
printf ( " 포인터의 변수 a의 크기 = %d Byte \n " , sizeof ( c ) ) ;

}
▶ 실행 결과
포인터 변수 a의 크기 = 4 Byte
포인터 변수 b의 크기 = 4 Byte
포인터 변수 c의 크기 = 4 Byte


위 예제에서와 같이 포인터 변수의 크기는 선언된 데이터형에 관계 없이 주소를
기억하는 데 필요한 크기로 int형과 같은 크기 ( 4 Byte )임을 알 수 있다. 여기서 크기는
시스템에 따라 달라질 수 있다.

포인터 변수에 주소값이 지정되면, 예를 들어,

int c , *ptr ;
ptr = &c ;

을 수행하면 다음과 같은 관계가 성립된다.

*ptr == c == *( &c )
&c == &( *ptr ) == ptr

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int x=100 , *ptr ;
ptr = &x ;
printf ( " x = %d \n *ptr = %d \n " , x , *ptr ) ;

}
▶ 실행 결과
x = 100
*ptr = 100



다음 포로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int a[ ] = { 10 , 20 , 30 , 40 , 50 } ;
int i , *ptr ;

ptr = &a[ 0 ] ;
for ( i=0 ; i<5 ; i++ )

printf ( " a[ %d ]=%d   a[ %d ]의 주소 => %x \n " , i , *( ptr + i ) , i , &a[ i ] ) ;

printf ( " &ptr = %x \n " , &ptr ) ;
printf ( " ptr = %x \n " , ptr ) ;

}
▶ 실행 결과

a[ 0 ] = 10 a [ 0 ]의 주소 =>194
a[ 1 ] = 20 a [ 1 ]의 주소 =>196
a[ 2 ] = 30 a [ 2 ]의 주소 =>198
a[ 3 ] = 40 a [ 3 ]의 주소 =>19a
a[ 4 ] = 50 a [ 4 ]의 주소 =>19b
&ptr = ffda  
ptr = 194  

 


위 예제의 실행 결과에서 각 배열 요소의 주소는 컴퓨터 시스템에 따라 다르게 나
타날 수 있다.

★ 배열과 포인터 ★

포인터와 배열은 밀접한 관계가 있다. 배열이 기억 장소에 기억될 때 배열의 요소들은
연속된 기억 장소에 기억된다. 그리고 배열명은 배열의 시작 주소를 가리키는 포인터 상수
이다. 그러므로 배열명을 기준 주소 ( base address )로 정하고, 배열의 각 요소가 몇 번째
요소인가를 나타내는 숫자를 더하여 줌으로써 배열의 요소를 포인터로 나타낼 수 있다.


< 1차원 배열과 포인터 >

다음과 같이 5개의 배열 요소로 구성된 1차원 배열이 있다고 하자 즉,

int a[ ] = { 10 , 20 , 30 , 40 , 50 } ;
int *ptr ;
ptr = a ;

a[ 0 ] a[ 1 ] a[ 2 ] a[ 3 ] a[ 4 ] 배열 요소
10 20 30 40 50 배열 요소의 값
ptr ptr + 1 ptr + 2 ptr + 3 ptr + 4  

와 같이 선언되었을 때 ,

*ptr == a[ 0 ] == *a == 10
*( ptr + 1 ) == a[ 1 ] == *( a+1 ) == 20
*( ptr + 2 ) == a[ 2 ] == *( a+2 ) == 30
*( ptr + 3 ) == a[ 3 ] == *( a+3 ) == 40
*( ptr + 4 ) == a[ 4 ] == *( a+4 ) == 50

이 성립한다.

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int i , a[ ] = { 10 , 15 , 20 , 25 , 30 , 35 } ;
int *ptr ;
ptr = a ;
for ( i=0 ; i<6 ; i++ )

printf ( " a[ %d ] = %d \n " , i , *( ptr + i ) ) ;

}
▶ 실행 결과

a[ 0 ] = 10
a[ 1 ] = 15
a[ 2 ] = 20
a[ 3 ] = 25
a[ 4 ] = 30
a[ 3 ] = 35

 


배열의 크기는 데이터형에 따라 달라질 수 있으나 , 그것이 몇 번째 요소인가는 데이
터형에 관계없이 일정하다. 예를 들어 다음과 같이 배열이 선언되어 있을 때 ,

char ch[ 3 ] = { 'A' , 'B' , 'C' } ;
int num[ 3 ] = { 10 , 20 , 30 } ;
float data[ 3 ] = { 0.5 , 1.2 , 0.75 } ;

각 배열의 요소는 배열명과 , 그 배열에서 몇 번째 요소인지를 나타내는 수를 더하여
표현할 수 있다. 즉 ch , ch+1 , ch+2 , num , num+1 , num+2 , data , data+1 , data+2
와 같이 나타낼 수 있다. 이들의 기억 형태는 다음과 같다.

메로리 주소 100 101 102 103
  Byte Byte Byte Byte
기억된 값 'A' 'B' 'C'  
배열 요소 ch[ 0 ] ch[ 0 ] ch[ 0 ]  
포인터 ch ch+1 ch+2  

문자형 배열의 경우 포인터가 1씩 증가할 때마다 메모리가 1바이트씩 증가된다. 배
열 ch가 char형으로 선언되어 있기 때문에 각 배열 요소간의 간격이 1 바이트이다.

메모리 주소 100 101 102 103 104 105 106
  Byte Byte Byte Byte Byte Byte  
기억된 값 10 20 30  
배열 요소 num[ 0 ] num[ 1 ] num[ 2 ]  
포인터 num num+1 num+2  

정수형 배열의 경우에는 포인터가 1씩 증가할 때마다 메모리는 2바이트씩 증가된다.
배열 num이 int형으로 선언되어 있기 때문에 각 배열 요소간의 간격이 2바이트이다.

메모리 주소 100 101 102 103 104 105 106 107 108 109 110 111
  Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte
기억된 값 0.5 1.2 0.75
배열 요소 data[ 0 ] data[ 1 ] data[ 2 ]
포인터 data data+1 data+2

실수형 배열의 경우에는 포인터가 1씩 증가할 때마다 메모리는 4바이트씩 증가된다.
배열 data가 float형으로 선언되어 있기 때문에 각 배열 요소간의 간격이 4바이트이다.
위의 그림에서 3개의 배열은 다음과 같은 관계가 성립된다.

ch == &ch[ 0 ] , *ch == ch[ 0 ] = 'A'
ch+1 == &ch[ 1 ] , *( ch+1 ) == ch[ 1 ] = 'B'
ch+2 == &ch[ 2 ] , *( ch+2 ) == ch[ 2 ] = 'C'
 
num == &num[ 0 ] , *num == num[ 0 ] == 10
num+1 == &num[ 1 ] , *( num+1 ) == num[ 1 ] == 20
num+2 == &num[ 2 ] , *( num+2 ) == num[ 2 ] == 30
 
data == &data[ 0 ] , *data == data[ 0 ] == 0.5
data+1 == &data[ 1 ] , *( data+1 ) == data[ 1 ] == 1.2
data+2 == &data[ 2 ] , *( data+2 ) == data[ 2 ] == 0.75


여기서 *( num+1 )은 배열 num의 2번째 요소값 20을 나타내지만 *num+1은 배열
num의 첫 번째 요소의 값에 1을 더한 21이 된다. 왜냐하면 간접 연산자 *가 산술 연산
자 +보다 우선 순위가 높기 때문이다. 포인터는 다음과 같은 연산이 가능하다.

① 포인터 변수에 정수를 대입할 수 없다. 0는 대입할 수 있다. 이것은 NULL
포인터를 의미한다.

int *ptr ;
ptr = 100 ; //에러 발생

② 포인터 변수를 증가 또는 감소시킬 수 있다.
ptr++ ;

--ptr ;

③ 포인터에 정수를 더하거나 뺄 수 있다.
num+2 == num[ 2 ]
num+i == num[ i ]

④ 포인터의 크기를 비교할 수 있다.
⑤ 포인터의 데이터형이 같을 경우 포인터와 포인터의 감산이 가능하다.


< 2차원 배열과 포인터 >

2차원 배열도 1차원 배열과 배열 요소들이 기억 장소에 연속적으로 기억
되므로 포인터를 사용하여 직접 참조할 수 있다. 2차원 배열은 1차원 배열이라
고도 할 수 있다. 예를 들어,

int a[ 2 ][ 3 ] = { { 10 , 20 , 30 } , { 40 , 50 , 60 } } ;
int *ptr ;
ptr= a[ 0 ] ;

에서 배열 a는 2개의 배열 요소 a[ 0 ] , a[ 1 ]로 이루어져 있다. 이때 배열명 a는 2차원
배열의 선두 주소를 나타내는 포인터 상수이며, a[ i ]는 제 i 행의 선두 주소를 나타내는
포인터 상수이다. 그리고 a[ i ][ j ]는 2차원 배열에서 i 행 j 열의 요소를 나타내는 변수이
다.

따라서 a[ 0 ]는 a[ 0 ][ 0 ], a[ 0 ][ 1 ] , a[ 0 ][ 2 ]로 이루어져 있고, a[ 1 ]은 a[ 1 ][ 0 ] ,
a[ 1 ][ 1 ] , a[ 1 ][ 2 ]로 이루어져 있다. 그리고 배열명 a는 배열 a의 첫 번째 배열 요소
a[ 0 ]을 가리키고 , 다시 a[ 0 ]는 a[ 0 ][ 0 ]를 가리키므로 배열명 a의 포인터의 포인터라
할 수 있다.
배열 a의 기억 형태는 다음과 같다.

배열요소 a[ 0 ][ 0 ] a[ 0 ][ 1 ] a[ 0 ][ 2 ] a[ 1 ][ 0 ] a[ 1 ][ 1 ] a[ 1 ][ 2 ]
메모리주소 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
                         
배열 요소값 10 20 30 40 50 60
포인터 ptr ptr+1 ptr+2 ptr+3 ptr+4 ptr+5 ptr+6
  a[ 0 ] a[ 0] +1 a[ 0 ]+2 a[ 0 ]+3 a[ 0 ]+4 a[ 0 ]+5 a[ 0 ]+6

그러므로, 다음과 같은 관계가 성립된다.

ptr == a[ 0 ] == &a[ 0 ][ 0 ] *ptr == a[ 0 ][ 0 ] = 10
ptr+1 == a[ 0 ]+1 == &a[ 0 ][ 1 ] *( ptr+1 ) == a[ 0 ][ 1 ] = 20
ptr+2 == a[ 0 ]+2 == &a[ 0 ][ 2 ] *( ptr+2 ) == a[ 0 ][ 2 ] = 30
ptr+3 == a[ 1 ] == &a[ 1 ][ 0 ] *( ptr+3 ) == a[ 1 ][ 0 ] = 40
ptr+4 == a[ 1 ]+1 == &a[ 1 ][ 1 ] *( ptr+4 ) == a[ 1 ][ 1 ] = 50
ptr+5 == a[ 1 ]+2 == &a[ 1 ][ 2 ] *( ptr+5 ) == a[ 1 ][ 2 ] = 60

ptr = a ; 는 ptr == a이지만 , ptr+1은 a+1과 같지 않고 ptr+1==a[ 0 ]+1고 같다.
ptr은 포인터이고 a는 포인터의 포인터이기 때문이다. 그렇지만 a[ 0 ]는 포인터이다.

다음 포로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int i , a[ 3 ][ 4 ]={ { 10 , 15 , 20 , 25 } , { 30 , 35 , 40 , 45 } , { 50 , 55 , 60 , 65 } } ;

int *ptr ;
ptr = a[ 0 ] ;
for ( i=0 ; i<12 ; i++ )

printf ( " %d " , *( ptr+i ) ) ;

}
▶ 실행 결과
10 15 20 25 30 35 40 45 50 55 60 65

 

< 포인터 배열 >

C 언어에서는 포인트형 변수의 배열도 사용할 수 있다. 포인터 배열은 여러 개의 문
자열 데이터를 취급할 때 흔히 사용된다. 포인터 배열은 포인터를 배열 요소로 하며,
사용 형식은 다음과 같다.

형 식
데이터형 *포인터배열명 [ 요소의 개수 ] ;

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int i , *ptr[ 3 ] ;
int a=10 , b=20 , c=30 ;

ptr[ 0 ] = &a ;
ptr[ 1 ] = &b ;
ptr[ 2 ] = &c ;

for ( i=0 ; i<3 ; i++ )
{

printf ( " ptr+%d = %u \t ", i , ptr+i ) ;
printf ( " *( ptr+%d ) = %u \t " , i , *( ptr+i ) ) ;
printf ( " **( ptr+%d ) = %u \n " , i , *ptr[ i ] ) ;

}

}
▶ 실행 결과

ptr+0 = 65478 * ( ptr+0 ) = 65486 **( ptr+0 ) = 10
ptr+1 = 65480 * ( ptr+1 ) = 65488 **( ptr+1 ) = 20
ptr+2 = 65482 * ( ptr+2 ) = 65490 **( ptr+2 ) = 30

 

이때 기억 장소의 주소는 시스템에 따라 다르게 나타난다.

 

★ 문자열과 포인터 ★

문자열을 1차원의 문자형 배열로 나타내면 문자열을 구성하고 있는 각각의 문자들은
배열 요소들로 취급된다. 그런데 문자열 자체를 배열 요소로 하는 문자열 배열을 이용
하면 더욱 편리하다. 왜냐하면 첨자를 이용하여 문자열에 엑세스할 수 있기 때문이다.

문자열은 포인터 상수이며 , 문자열 배열은 이들을 배열 요소로 하기 때문에 포인터
배열이라고 할 수 있다. 문자열 배열의 선언 형식은 다음과 같다.

형 식
char *문자열배열명 [ 요소의 개수 ] ;

예를 들어 ,

char *name[ 3 ]={ " hong " , " kim " , " park " } ;

와 같이 선언되었을 때 , 포인터 배열 name은 3개의 요소로 이루어져 있으며 , 이들 요
소들은 문자열의 시작 주소들을 기억한다. 이것을 그림으로 나타내면 다음과 같다.

포인터      배열요소
name == name[ 0 ]
name+1 == name[ 1 ]
name+2 == name[ 2 ]


*name
'h' 'o' 'n' 'g' '\0'


*( name+1 )
'k' 'i' 'm' '\0'


*( name+2 )
'p' 'a' 'r' 'k' '\0'

그러므로 다음과 같은 관계가 성립한다.

*name[ 0 ] == **name == 'h'
  == *( *name+1 ) == 'o'
  == *( *name+2 ) == 'n'
  == *( *name+3 ) == 'g'
  == *( *name+4 ) == '\0'
*name[ 1 ] == **( name+1 ) == 'k'
  == *( * ( name+1 )+1 ) == ' i '
  == *( * ( name+2 )+2 ) == 'm'
  == *( * ( name+3 )+3 ) == '\0'
*name[ 2 ] == **( name+2 ) == 'p'
  == *( * ( name+2 ) +1 ) == 'a'
  == *( * ( name+2 ) +2 ) == 'r'
  == *( * ( name+2 ) +3 ) == 'k'
  == *( * ( name+2 ) +4 ) == '\0'


다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

char *name[ 3 ]={ " hong " , " kim " , " park " } ;
int i ;
for ( i=0 ; i<3 ; i++ )
printf ( " %s \n " , name[ i ] ) ;

}
▶ 실행 결과
hong
kim
park


★ 이중 포인터 변수 ★

이중 포인터 변수란 포인터 변수에 다시 포인터를 지정한 것을 의미하며 이것을 포
인터에 대한 포인터락 한다. 사용 형식은 다음과 같다.

형 식
데이터형 **포인터변수명 ;


예를 들어

int **ptr ;

라고 선언하면 , *ptr은 포인터 변수 ptr이 가리키고 있는 주소의 값 즉 *ptr이 가리키
고 있는 위치의 주소의 값을 나타낸다.

다음 프로그램의 실행 결과를 나타내시오
▶ 프로그램
# include < stdio.h >
void main ( void )
{

int i , *p , **ptr ;
i=100 ;
p=&i ;
ptr=&p ;
printf ( " i = %d \n *p=%d \n **ptr=%d \n " , i , *p , **ptr ) ;

}
▶ 실행 결과
i=100
*p=100
**ptr=100


이것을 그림으로 나타내면 다음과 같다.

2060 2022 1020 메모리 주소
2022       --------> 1020         --------> 100 기억된 값
변수 ptr 변수 p 변수 i  


여기서 이중 포인터 변수 ptr은 포인터 변수 p의 주소를 기억하고 있고, 포인터 변
수 p는 변수 i의 주소를 기억하고 있다. 그러므로 **ptr은 ptr이 가리키는 주소의 값
( *p )이 가리키는 주소의 값 , 즉 변수 i 의 값이 된다.


★ 포인터와 함수 ★

함수 포인터는 수치 해석 분야에서 자주 사용하는 개념이다. 함수 포인터는 함수값
을 나타내는 포인터이다. 일반적으로 함수명을 수식 내에서 사용하면 그 함수를 가리키
느 포인터로 자동 변환된다.

함수 포인터를 사용하기 위해서는 먼저 사용할 포인터를 선언해야 하는데 그 형식은
다음과 같다.

형 식

● 호출 프로그램 ( calling program )
데이터형 *함수명 ( ) ;

● 피호출 프로그램 ( called program )
데이터형 *함수명 ( 매개변수리스트 )
매개변수리스트의 선언 ;
{

}


먼저 함수 포인터를 선언하려면 다음과 같이 정의해 준다.

형 식
데이터형 ( *포인터함수명 ) ( [ 매개변수리스트 ] ) ;

예를 들어,
int ( *func ) ( ) ;

라고 선언하면 , *func는 func가 가리키고 있는 주소의 값을 나타낸다. 이때 * func에
있는 괄호를 생략하면 int형에 대한 포인터를 반환하는 함수를 선언하는 것으로 인식한
다. 함수 포인터가 특정 함수를 가리키게 하기 위해서는 함수 포인터에 함수명을 대입
하여 초기화한다. 이때 주의해야 할 것은 함수명에 대한 함수 선언을 먼저 해 주어야만
함수명을 대입할 수 있다는 것이다. 즉 ,

int sub ( ) ;
int ( *func ) ( ) ;
func = sub ;

와 같이 선언하면 함수 포인터 변수 func는 함수 sub을 가리키는 포인터를 기억하게
된다. 또한 포인터 변수를 통하여 간접적으로 함수를 호출하려면 변수에 간접 연산자
를 사용하여 매개변수들과 함께 쓰면 된다. 그 형식은 다음과 같다.

형 식
( * 포인터함수명 ) ( [ 매개변수리스트 ] ) ;

예를 들어

double ( *ptr ) ( ) ;
double sin ( ) ;
ptr=sin ;

와 같이 선언되어 있다면 ptr=sin은 함수 sin( )이 위치에 있는 코드 세그먼트 영역
의 선두 주소를 대입하라는 뜻이다. 이때 함수명 앞에 주소 연산자 " & "를 사용하지 않
는다. 만약 이때 주소 연산자를 사용하면 에러가 발생한다.

ptr ---------> 함수를 가리키는 포인터를 의미
*ptr --------> 함수 자체를 의미
( *ptr ) ( x ) -----> 함수를 호출한다는 것을 의미

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
int plus ( int x , int y )
{

return ( x + y ) ;

}
void main ( void )
{

int ( *func ) ( ) ; // 함수의 원형
int a=10 , b=20 , c ;
func = plus ; // 함수 plus의 주소를 함수 포인터 변수 func에 대입
c=( *func ) ( a , b ) ;
printf ( " %d + %d = %d = %d \n " , a , b , c ) ;

}
▶ 실행 결과
10 + 20 = 30


< 함수 배열 포인터 >

함수 배열을 가리키는 포인터의 선언 형식은 다음과 같다.

형 식
데이터형 ( *포인터함수명 [ 첨자 ] ) ( ) ;

예를 들어,

int ( *func [ 5 ] ) ( ) ;

와 같이 선언하면, 함수 배열의 결과로 정수형의 함수 배열 요소 func [ 0 ] ( ) ,
func [ 1 ] ( ) , func [ 2 ] ( ) , func [ 3 ] ( ) , func [ 4 ] ( ) , 5개가 준비된다. 그리고 , 함수 배열 포
인터를 사용할 경우 ,

int ( *func ) ( ) ;

는 int형 func가 가리키는 함수를 의미하고 ,

int *func ( ) ;

는 int형 포인터를 되돌려 주는 함수를 의미한다.
그리고 ,

int ( *func[ ] ) ( ) ;

는 int형 함수 배열 포인터를 의미한다.

다음 프로그램은 함수 배열을 가리키는 포인터를 사용하여 두 수 a , b의 값을 키보
드에서 입력받아 산술 연산을 수행한 결과를 나타내는 것이다.

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int a , b , p[ 5 ] , i ;
int plus( ) , minus( ) , multiply( ) , divide( ) , remainder( ) , ( *ptr[ 5 ] ) ( ) ;
ptr[ 0 ]=plus ;
ptr[ 1 ]=minus ;
ptr[ 2 ]=multiply ;
ptr[ 3 ]=divide ;
ptr[ 4 ]=remainder ;

printf ( " 두 수 a , b의 값을 입력 : " ) ;
scanf( " %d %d " , &a , &b ) ;

for ( i=0 ; i<5 ; i++ )
{

p[ i ]=( *ptr[ i ] ) ( a , b )
printf ( " p[ %d ]=%d \n " , i ,p[ i ] ) ;

}

}
plus( int x , int y )
{ return ( x+y) ; }

minus( int x , int y )
{ return ( x-y) ; }

multiply( int x , int y )
{ return ( x*y) ; }
divied( int x , int y )
{ return ( x/y) ; }

remainder( int x , int y )
{ return ( x%y) ; }

▶ 실행 결과

두 수 a , b의 값을 입력 : 30  6   Enter Button Push
p[ 0 ]=36
p[ 1 ]=24
p[ 2 ]=180
p[ 3 ]=5
p[ 4 ]=0