|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
前言
: B: {5 p* G) S) W函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。
; M3 }1 i1 d: ?) p8 r" X' K$ s8 c今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。
: ~6 @, D( E7 ] t. p1 T" j
+ l0 ~! |) B/ D. b正文) v' ]8 K4 D5 c6 v2 O8 R. w
先来看看两者的定义以及说明。# N4 c' Q" I! g; Q1 U
; ?) W5 x; K9 u% i+ z _指针函数2 {3 {8 X& q1 R
定义
' o x( _0 {$ @' l- b9 W0 y* Q指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。 ?# O. M* y2 F1 b
声明格式为:*类型标识符 函数名(参数表)
# B) e+ w( B+ |' k, ^3 V' _
$ }/ j7 I! f' n( E" F% {这似乎并不难理解,再进一步描述一下。# G) F7 T5 T) m# e3 p' U- v
看看下面这个函数声明:
9 a0 I# [% U Z* N# F
5 t, [" X+ f7 W4 p$ q' d0 v( pint fun(int x,int y);
# G: q Q2 A2 R- F% k0 Q$ c5 N# {2 k3 t* Y) T8 L$ |4 {4 f. G
这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。
4 W5 d. A, ~( a# j. ? H8 B" y接着看下面这个函数声明:
6 j6 _) |0 {' H1 [& \1 d0 d
. ^) x; P9 h+ _ W& Cint *fun(int x,int y);
; T( A: s4 P0 C4 z: H5 l7 A- G/ o& |) i2 i5 ?
这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。
i& r# v: t& O6 p. Z( l0 _# G6 ?/ |. h; P- _; @
这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。
2 n/ @& Q" `' K' y
6 @# J2 ~& k' d指针函数的写法/ |# w( n( q" w1 s" C
int *fun(int x,int y);4 B: q \7 _( N# m" T
int * fun(int x,int y);
+ [/ \( V- g) z7 q6 y- h8 Lint* fun(int x,int y);8 S; a5 j* f6 v& b5 t# y4 j" S" {0 p1 u
, o: q$ r+ i! W; _
这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。2 ^* Y! g `5 g; Q# v
* s4 ?; M# l# I5 x% I! M
示例; I; _3 F1 W5 X8 z! n6 P
(由于本人习惯于 Qt 中进行开发,所以这里为了方便,示例是在 Qt 工程中写的,其语法是一样的,只是输出方式不同)# |3 d: U$ X0 w, E
来看一个非常简单的示例:# l- m# u/ ` P8 B9 `3 H
+ G- Q8 H+ _4 O$ `$ y+ @- S# Vtypedef struct _Data{
1 r) Q4 M, z2 K8 v int a;
h( K/ t/ N$ J int b;
+ j, \% }' V1 @/ T7 n4 h* j}Data;% A3 F: m; X) u( r. q/ ~
j, F4 V [8 O. e. r$ r: Z% [. ]$ D
//指针函数" p6 i6 n4 y' o* M: _3 {
Data* f(int a,int b){+ W: R, I- T! |6 E- J6 O. I
Data * data = new Data;7 a5 L( D( S! b1 p4 P, r, W5 c5 K
data->a = a;5 _- T) q- J: n+ D5 Z. O) s6 g
data->b = b;
' ?; ~4 p$ K! G8 x; Y2 l return data;4 }2 d* |+ z8 L; I
}1 [7 ?6 G0 W7 {& u9 p: s7 |! }
, H( Z# k" N# q0 T/ p& m! i; v
int main(int argc, char *argv[])/ M2 E5 p2 |' f
{
+ a% ^6 [1 v2 V" u1 v QApplication a(argc, argv);" C( M" Y5 ]$ h$ e1 p7 h; v* I
//调用指针函数, d3 y( V; W- g a, y
Data * myData = f(4,5);* N$ A' W w9 `- b2 i
qDebug() << "f(4,5) = " << myData->a << myData->b;
2 u- Q% ~- g' o% a$ U' Q$ G1 D/ n: F* ~/ w
return a.exec();6 E' J; ~3 N5 D; l
}
; K; @; i8 Z! v, S0 s
8 N# Y# T6 b, y其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。
) B5 V$ {: b0 j% X3 P' w* s2 \3 S$ r0 j1 A
函数指针9 R! a" [3 z6 Z4 f4 U" Z
定义
2 s1 `% z* a/ R2 c+ X7 p: V函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。
! i. I6 @5 [/ `2 S: \+ X声明格式:类型说明符 (*函数名) (参数)5 b; k; r; c0 B
如下:# X- w, [& K+ Q+ q
" n; L! n) B" s7 k! Z1 w5 Dint (*fun)(int x,int y);
' L) F& A( O9 r! Q( J' E' k- C4 N- {+ m- t% T
函数指针是需要把一个函数的地址赋值给它,有两种写法:" H8 L I, Y0 P1 x% n" t3 D
3 c2 K3 s3 }) I2 Y9 e& nfun = &Function;, g/ X- `, X- Q' Q8 R5 G: L
fun = Function;
7 q0 X" n1 m) ^* l6 G6 h) a U! e' ]& P4 F& A
取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
7 I2 @& W. e1 z; c% \6 ~% w+ q% U
调用函数指针的方式也有两种:& a5 S- l# F0 l d& c1 A5 }
& X' w# v, `( ?x = (*fun)();
+ o/ j5 d6 P: i& Zx = fun();
' W0 u# `+ o2 ~3 x" V' G5 S$ ]) e$ k% ^3 m4 t' x2 C% z9 C
两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。
. y3 D0 }" z, H4 O
: k& c$ o( F( B8 m3 Z5 b示例
: z& W- w5 \+ a3 i! Bint add(int x,int y){
6 }6 @; E' ]! y return x+y;) ~- r6 |& j2 U! G8 J6 U; ^
}
- S' e w: D4 b0 G' n S8 uint sub(int x,int y){5 S: e+ ]& l# d6 k5 Y A3 t: |
return x-y;1 r4 l* b" n$ M
}
% n+ ?* z/ c' N3 S0 s, Z0 P//函数指针! U( |2 [% |! h5 {# ?7 g+ b
int (*fun)(int x,int y);
8 U- ~: E/ V8 _3 W# ^+ w
* o5 O) b3 g, I( @: R, j, hint main(int argc, char *argv[])8 X( `1 z: K( Y: Z
{1 D( t) ~6 V$ H+ s) B
QApplication a(argc, argv);8 T4 M" j8 r0 ?$ f3 d8 L2 \( T, f! i
//第一种写法
, b8 {, w+ `# W6 J; ?1 ~ fun = add;$ W$ |9 }( J- K: |. u
qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ;) F$ S- a q2 h% ?; c# Y& E& c
//第二种写法7 M4 O3 \& E1 ~8 y4 Q/ ?( n0 e+ S
fun = ⊂
2 o& I! ?! a7 o qDebug() << "(*fun)(5,3) = " << (*fun)(5,3) << fun(5,3);/ u% s! k; s- ?- p% X! P& G" |
2 z! ~, d' Q) l; U$ g return a.exec();
9 p& k2 E7 s! M% w, e}. _( J. C5 h1 U3 x6 f, r6 Z
, E8 ]3 Q; Y! Q! J* n- ]6 }# }3 n% H
输出如下:
# }* C" V4 s& a" Y# g4 s' ?, f; L2 a* F
(*fun)(1,2) = 3
: s2 r- B& Q8 g0 }6 J(*fun)(5,2) = 2 2" h$ y! _ E$ U ~
; r( Z2 Z2 N" F, `/ M
上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。4 k5 H5 Q" ~% z& Y; R, f( ?5 h
9 o) A" u1 m7 v; w. [
二者区别
+ e+ g, w* W j1 d( s9 V通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:, Z; N( ^, h z' L! S* N" a9 v! ], G
4 K P4 f" F& t3 J y
定义不同
! x8 a9 f" Q" q9 o指针函数本质是一个函数,其返回值为指针。: G/ o7 T, P/ {2 L: ^
函数指针本质是一个指针,其指向一个函数。0 t& W) @7 z! J* q
/ k- l1 p! l. }, P
写法不同6 X% _+ L8 `# B+ G6 x
指针函数:int* fun(int x,int y);) V; s: k, F9 l" l' K* g
函数指针:int (*fun)(int x,int y);
0 [0 I0 D* }( l% r8 g) P. _可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。+ y6 n% d6 [( m3 C- ?
再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。. k% _0 ] I+ @/ u
2 B0 z' n& v, z x+ ^' @用法不同 k/ _4 ?! t8 B3 [
上面已经写了详细示例,这里就不在啰嗦了。
1 R. k" q' z, D" L: F
3 B9 B9 b( {8 y" k3 { g总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。( x( w5 C, F# Y( `' n- S8 a
9 J/ e$ t. |& Z" L9 u8 }
8 W$ g$ C* I2 t; c |
|