| 
 | 
	
    
 
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册  
 
x
 
前言$ n/ K6 ^, K# |( r2 o 
函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。 
' A2 E; H! ~% m0 y6 ^& F+ o, e今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。 
/ z/ ?& X# q; e( m* X/ h& |1 I! N7 {9 t( ^7 S 
正文! H( d4 [2 `" B" }* c0 S& T 
先来看看两者的定义以及说明。 
# }4 s6 o$ Z& A+ ]4 Q* e' B 
1 [* J& T+ w. C8 Z# ?指针函数" t. m9 O, Z: f+ Z" j% Q+ ` 
定义* o* J7 A- ]& [3 \, ]) B& l 
指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。 
/ |0 t+ C7 `6 l+ Z$ }声明格式为:*类型标识符 函数名(参数表)3 R4 a# Y3 A" d& r5 I! m9 U 
 
7 [- J9 ~1 S% _1 d0 d" l这似乎并不难理解,再进一步描述一下。# n# @5 Q3 n- @* g( U( V0 | 
看看下面这个函数声明: 
) `( [8 a9 g9 O, U! Q 
6 l8 n) L1 X! o. ~3 {6 a; {int fun(int x,int y);4 F8 C+ S3 e- I9 E6 G) u 
 
& H6 n$ Y& D3 h, d5 ?. v这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。 
5 `6 _$ w: _& I) ~$ \# q* B7 I. |接着看下面这个函数声明: 
0 {1 K6 ^) e* _; ~; v: [, z  h) I8 i9 d5 r 
int *fun(int x,int y);$ p& S$ P: X' \7 K9 p 
 
  Q2 }( }0 q  y: a/ x8 K. P! G这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。; C0 [- A# l; A7 \  V1 e6 ~! V# ] 
 
( ?6 @6 e# B$ u& q这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。4 D8 M3 M, B) v% ~) p0 K0 a 
 
/ I: o# Y. k& C8 t, T5 j7 ^* C指针函数的写法& ?$ c) r+ F, c8 C8 u 
int *fun(int x,int y);4 E/ B+ r" R! z" N# I$ S& J/ p3 c 
int * fun(int x,int y); 
0 G0 W# `$ m3 H, W7 ~( |1 iint* fun(int x,int y); 
, Q3 R* q7 D; \& @1 K0 u( @3 _ 
, g4 D! b) \$ S3 O4 N# V8 r+ [这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。9 D. Z4 J! |  h2 `3 x2 f$ F1 a 
  ]. @. m1 A* E$ a 
示例1 _; G# Y6 O7 S; G* X% X$ b0 I 
(由于本人习惯于 Qt 中进行开发,所以这里为了方便,示例是在 Qt 工程中写的,其语法是一样的,只是输出方式不同) 
% X. \4 L; G6 M( ~7 n3 u& `1 v3 }来看一个非常简单的示例: 
9 {% K, j& S6 U' P# u$ R4 T2 p 
3 f- x' t( X' j: l$ d  d/ W. Utypedef struct _Data{0 M; l' Y. q/ d% z1 x+ @# [/ y 
    int a; 
# r* P2 |/ `) A3 U    int b; 
9 f( T- g3 H) R, I7 q}Data;0 Z" S% z6 a6 n, I) g2 t# c  ~$ U 
2 G9 a1 m0 N0 s7 ^/ Z+ Z) k 
//指针函数 
, w( c; z! ]/ J" \Data* f(int a,int b){ 
' R; z9 e9 s* E6 a    Data * data = new Data; 
5 @) s; r2 C, o$ G0 Q    data->a = a;( O) e1 O5 \( |- G) w 
    data->b = b; 
" `$ c4 G& Y. N  x  y( `% c    return data;- S' c8 c% w5 e! P! ?! }; I, @ 
} 
" g, u0 r7 Z/ E" W' C: }( _ 
  p7 W- P, ^/ U- U. z, Z% v. yint main(int argc, char *argv[])+ b! e4 |& C% T8 }# n 
{ 
" P# V# V  x' d5 h4 }4 `( Z# c9 O    QApplication a(argc, argv);$ V8 N, {1 h+ k* t 
    //调用指针函数 
$ R7 M; \+ g' L/ K# i    Data * myData = f(4,5); 
% m3 j3 s1 \0 J    qDebug() << "f(4,5) = " << myData->a << myData->b;" F3 \* u8 ?1 b1 O8 Z1 v 
: |! s8 W) a9 k( l 
    return a.exec();, N. L* c3 I0 U& d' E2 S 
} 
5 H  h7 q8 r7 f$ }3 P/ s 
2 }7 W2 |  h, a- u8 m其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。 
. r, l7 I  H4 V4 v( @6 W. Y. \5 r- O- w* T- g0 O# p3 c 
函数指针5 c+ M* s4 z" e 
定义 
1 q8 X3 z% `3 k  g# q函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。3 v$ B) I0 D+ U" x 
声明格式:类型说明符 (*函数名) (参数)" U& w+ o% Y9 |4 o 
如下: 
5 ?( o; t2 u3 W. ?+ x1 t0 z 
7 D7 o1 |6 V6 \( a! lint (*fun)(int x,int y);: O0 C' c' f. `& @: n9 n( x 
 
. |) `$ E0 ]7 t. _. U5 S4 V: O函数指针是需要把一个函数的地址赋值给它,有两种写法: 
9 {& O& P. Q8 P  V9 T) | 
, v6 j+ R( m% mfun = &Function;; |- \  K8 p  P( d7 { 
fun = Function; 
7 `$ J: ~9 u3 [6 L% G) v7 G4 q9 r, J0 s, T- m/ _5 ]- h 
取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。3 U& u6 f. Q( L# `8 ^ 
 
0 z+ U( f: v! h% L调用函数指针的方式也有两种:& c# f/ Z3 |1 ^& H% ] 
& K) J3 Z9 b. z" y+ \+ |& R- O 
x = (*fun)();; t- o, f# S3 X; h$ i 
x = fun(); 
- y7 m1 z! X+ d% E$ {" Y) ^+ t. d4 X. \7 m, X( _0 O 
两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。( x% T( t5 [1 q3 z( b, U 
9 ~( ^) Q! C+ u' W  L# d 
示例 
5 r9 t0 s# r# C$ m. L; ~( Lint add(int x,int y){$ c) p. b" y4 M( o# c% Y6 S 
    return x+y; 
0 b. x  E7 F9 Q5 S+ k0 M, U# _8 Y}4 e3 h% Q+ p/ P2 A  Q. u$ W4 C 
int sub(int x,int y){3 k. m  ~/ {+ b1 w7 o* y1 H 
    return x-y;) p7 i9 R. z( \2 x# } 
} 
9 _& J/ R0 }. T8 g  t8 S8 k1 r. z//函数指针$ s8 l* C5 ?- A 
int (*fun)(int x,int y);* ], g/ h/ l9 d5 b% W; e9 e% _; Y 
 
- `8 h% m+ E0 h% B8 P) P4 V; C/ Eint main(int argc, char *argv[]) 
* O; c7 I' d/ s( y6 q7 {3 `{0 ^) H$ U. P3 E9 S  e! D) | 
    QApplication a(argc, argv); 
8 {+ {) }. B* H    //第一种写法 
( b! W0 F5 S- j& b" R% `2 n    fun = add;5 F3 W; Z% M2 a( ?: F. c% s 
    qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ; 
  ^# \; b% J; k5 G: S        //第二种写法2 y, w6 n. q* m8 O 
    fun = ⊂- {; u# e% }/ M! W7 Q# u" h 
    qDebug() << "(*fun)(5,3) = " << (*fun)(5,3)  << fun(5,3); 
5 v7 Y3 F; y7 p5 ?3 D: s6 E4 E; i3 t- S% Q" _9 p 
    return a.exec(); 
! _8 m* H* ?; X# ^2 w}+ [, o; b/ U" D 
 
( t1 W9 N9 }. n5 ]7 u& ? 
% Y+ X1 a$ e! u. f2 s/ h3 `输出如下:6 D0 C: W7 n  J6 Y/ p" S 
 
8 t/ I! V+ A+ c(*fun)(1,2) =  38 G  X" W2 [2 Q$ r8 U0 z 
(*fun)(5,2) =  2 22 y1 m7 {8 k. h' |0 P  L 
 
  B, C) U4 l+ Y上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。 
% H6 _$ A3 M# c2 O 
" \, Q4 z7 y: ^6 c) v二者区别; _  p1 y$ a6 J% z% y9 H 
通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:$ D! k5 b2 i2 ^( Q( G  x7 t6 J' h 
( X7 `" O+ T" L- A' q5 h4 \ 
定义不同 
* v* I" `5 J% E! H4 ~! u" l指针函数本质是一个函数,其返回值为指针。 
1 S9 f% u/ i0 Y  j6 r: q. V6 K函数指针本质是一个指针,其指向一个函数。 
) y) Y6 F2 n/ ~3 y3 ]( B/ y( h. h 
# b9 a+ @. }4 \/ n  |. m, K' W  k) d写法不同: s) `* s7 I# J* g. i- [* V 
指针函数:int* fun(int x,int y); 
# S" R5 f+ z: b$ Y& h' X  [函数指针:int (*fun)(int x,int y);2 ^4 o# S4 t# d% k( U, r 
可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。, X. \# z1 s/ U; y" n 
再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。* n8 \% m1 r; I+ g! m 
 
/ Z' W& |& W  ^8 q# R用法不同 
% `) i) H. o' h% Z" z7 w3 G上面已经写了详细示例,这里就不在啰嗦了。 
( v, q, s3 F/ K$ i/ ~4 N/ ~  x3 V7 k6 ? 
总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。 
1 M  s& b+ v& K4 J. ^8 N5 A/ r 
2 C- Z, v+ b3 B0 K% ?5 n 
8 q  c, f' Q: t |   
 
 
 
 |