|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
前言* d' {/ M. X& c N6 h v% j
函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。
/ d/ p- c) ?( N! Y今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。
! \5 ?5 G( _* g; q* e
8 C* _- A& _# W5 o正文
, @ V$ H5 m' v+ V. v$ s8 |先来看看两者的定义以及说明。
A3 F0 M) T" m. |" @/ h& Q" Z5 }2 q: n% s4 ^6 r
指针函数
. W/ j/ s U( s3 o v# R& ]" L定义+ _! c: u0 u+ N, U& h9 @
指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。2 ^- b$ K) E* N/ v+ X
声明格式为:*类型标识符 函数名(参数表); m% t' R2 w( g; C7 } `9 h
; I0 S# k0 c# W
这似乎并不难理解,再进一步描述一下。$ @& v w7 X9 \1 X1 Q
看看下面这个函数声明:9 c+ F% y I* Z
9 z# N9 H2 V B4 F7 D- o* E
int fun(int x,int y);7 T& J9 E: z( D; U* |/ ~# d" W
. \( A/ l) N2 W6 O) x这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。3 c% ?+ N* i, {; d
接着看下面这个函数声明:' H% M2 p0 r; P9 q/ v6 k
. u9 X7 G4 w2 C( f' i/ {$ o& I
int *fun(int x,int y);: z+ P& e4 s# X# W* H" C5 P9 M) b) D
( Y2 Q9 C4 |: M% }
这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。/ K4 i) o# R3 F- r6 m& v
( P3 }- k" ?9 O9 X, r这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。
8 h: v+ l* z' g/ Y7 q/ w/ S$ D1 T6 ]9 V
指针函数的写法1 L7 @: W' P; p3 t+ O, J$ o! F' Y$ O% M
int *fun(int x,int y);
: E5 c% a! B7 O1 J1 b5 V S, Jint * fun(int x,int y);
0 c/ m, Y$ @6 dint* fun(int x,int y);
4 K# T5 k0 K2 f4 |- h/ r
$ p8 o' I0 S7 Z! ?4 `这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。% e0 a% [/ h/ X/ x% i/ ^/ O
; ~) j/ k @5 G, a* Q
示例
" B0 E1 H K! h9 B(由于本人习惯于 Qt 中进行开发,所以这里为了方便,示例是在 Qt 工程中写的,其语法是一样的,只是输出方式不同)& I. F0 W$ t6 d* E0 @; w$ q
来看一个非常简单的示例:
: _* O+ _' l9 t- ~! u. f q& o: J$ M
* X8 G% U4 K2 Atypedef struct _Data{
# s1 i1 Q+ F \. P int a;
2 x7 J5 ~% {; C* n int b;0 n0 P1 G5 I1 D: I# R; M! U6 K
}Data;
' p' f' W d, R6 f/ U$ t+ `5 V
) P- ^7 P* o/ w8 ^//指针函数
8 V+ _2 a& i4 {. K0 lData* f(int a,int b){
# X# L+ k: v# j2 b! k$ q$ b( ?1 i+ Z Data * data = new Data;* n, H, d& R& b5 R1 |
data->a = a;2 G/ R& M- Q8 e- k
data->b = b;7 H+ g. D8 ~0 W" ]& r& d5 Q' I3 k
return data;3 F1 n% u; T" w s1 a+ s% `1 V7 V
}& X5 D3 M2 I* ?' g/ U
* _$ h# r6 r1 P- x/ dint main(int argc, char *argv[])
4 G) O H, [, R& ~" t5 E2 h{
% h( H4 l' {; B0 S1 j( U. A QApplication a(argc, argv);
6 O2 g* H0 n1 r/ `% ^/ y //调用指针函数
" `' v9 w9 u5 r% x. x3 S Data * myData = f(4,5);
3 L u' b+ R v! d, t qDebug() << "f(4,5) = " << myData->a << myData->b;6 G! ~5 a5 j, c* x; _1 R! N
8 [: d8 v b( A: r) t! ]9 ~8 V return a.exec();
3 S$ q. ?. i! S% A}
) E0 w, o3 ?" n
; Q o; x; E. m# M1 @ W2 W" d9 x其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。
% f7 a5 B- B( G9 X- W. n# @
2 T# I; |# h+ v: g9 L函数指针
2 S8 v( e7 K, A" q8 h/ ?定义
4 V5 A: N4 g6 D T4 ~) n- e函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。
) a; k! J& I- K- K" N7 D声明格式:类型说明符 (*函数名) (参数)
% P! M; V* F" N" ?' p2 K! i9 @如下:5 D. j! H* X7 Y1 f
8 w5 L0 f8 K+ u s4 |
int (*fun)(int x,int y);
" X" N1 f( S c! W; L/ Z3 d' n( g
* {4 N1 |; T0 ?: v- @函数指针是需要把一个函数的地址赋值给它,有两种写法:
$ f# @" k1 r% C6 U2 M
# r* J/ ]! `. T8 l% ^# ~) L, qfun = &Function;
- k. |& u+ i9 B3 b, }1 q3 Ofun = Function;
) j7 E1 N7 u/ a" t. [4 j4 G: f
3 q, G" n8 ]$ f' l4 l0 y取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
" }7 m& ?6 Q% E7 G, k0 ~; W o; j" h& b
调用函数指针的方式也有两种:
3 q1 m2 o. @' j0 q7 h( Y+ |. t. U; t: \5 k. e6 b( D
x = (*fun)();- I. ?9 W3 H! P$ g2 s/ j! L) ]$ J
x = fun();1 f2 t) g& o2 T3 ]
; E- }! N* j( q: s' t两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。
) I+ ~. X6 d# k! K) ^6 l+ s5 c& y- B; Q/ H4 m9 T! c
示例1 m. @" _3 I" }: D! ]
int add(int x,int y){
+ x; H3 ? C7 F7 K return x+y;3 K4 t! j* A) T& a
}
& M% v$ W+ y. j8 g h z( k) Bint sub(int x,int y){) T7 L/ E1 r: z3 r) D
return x-y;
( N0 H, g, w5 K9 t+ S. z9 c/ _}+ O( D8 K/ d4 X5 I5 \
//函数指针
& H5 w- ~& y9 T8 Tint (*fun)(int x,int y);7 T* d4 T3 }* L6 R& q
" J3 ?8 N" N5 J) {+ g5 f
int main(int argc, char *argv[])
3 |( }6 L b9 i! _# f9 U6 i{4 o* j3 n5 b* i, S
QApplication a(argc, argv);" a9 M. b% Y4 [( }
//第一种写法
2 S' v; ^- x9 x9 _$ { fun = add;% k) W# T8 r+ W0 X
qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ;1 B* w4 I5 ]% f6 k+ w" H
//第二种写法) J2 A1 g! m+ y# v9 ]# A# j
fun = ⊂
' o6 }7 l( ]2 b/ j5 B# c. _4 I qDebug() << "(*fun)(5,3) = " << (*fun)(5,3) << fun(5,3); _8 Q/ r p8 A' g6 N
! B6 v- k/ J7 Z- } return a.exec();$ C' e4 h! f2 Z& l2 w2 Y' C
}* W+ ~3 H; u( c# F; s1 k
3 r* V6 ^+ m" l R" `; k
, Y% O4 x' ]6 h& A: q
输出如下:( b! D$ P9 B& s) v3 j/ y
, T/ c2 I! t' L2 ~4 _) B
(*fun)(1,2) = 3
; y8 f" J" S! ]2 B5 O(*fun)(5,2) = 2 2# y% {3 Q6 E. a' u v- |
1 M1 v( v! O6 Y+ r上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。' U# {8 r+ e* Y0 E W
n P3 |: y$ ~$ [! E% o二者区别: P7 _0 d0 S" c1 @4 g
通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:
( `* p) V$ U" K+ R
- ]& L/ O# {3 w3 I) M3 P5 X2 c- `0 B定义不同
' @/ d' F* {+ `2 ?( }( a J指针函数本质是一个函数,其返回值为指针。8 I: ]- l0 `) @/ ~
函数指针本质是一个指针,其指向一个函数。
4 B4 {5 J2 W, I4 l8 N2 M1 n& p7 u6 v: @* N, o
写法不同
* f- i& k" l7 ]2 E8 U2 ^' L" z指针函数:int* fun(int x,int y);- G* }" T6 W+ x% J6 V8 T5 ]- h
函数指针:int (*fun)(int x,int y);3 \3 M, H( j" Z P
可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。) |8 x4 R2 Q0 N8 d5 V
再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。9 d! H( Y! t7 Y/ T) e1 b
5 y6 @7 ?- e$ N! S7 ?; E
用法不同
g) {8 W: p) u, E0 F9 Y. O$ T上面已经写了详细示例,这里就不在啰嗦了。9 N0 X, j; p$ I% k
+ f A4 u% v! j( O
总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。
7 [$ ^4 } y9 Y
" Y. c+ F8 z2 D' k2 B' S6 M2 X; V" c1 s) y) G8 b# n
|
|