|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
前言
: f) y# X- y) C: ^9 O% a: J函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。: C' n1 P3 U( `3 a
今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。
& ?2 @) z8 B% S" A$ x. R' Z/ [1 P5 {# q6 J/ H$ N6 h4 b
正文
u( x9 S: Q" l2 h0 U0 c先来看看两者的定义以及说明。% Y7 _; |7 m' \, R9 a5 Q
& L$ i* Z# B* [+ |4 E6 O' s指针函数! b3 A1 b" d& Z0 f; _. {
定义
6 Y4 z7 a6 [, M& q5 L指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。. K0 F3 @+ H5 ?1 [ B
声明格式为:*类型标识符 函数名(参数表)
' U/ z T( d* q+ k1 n6 d
8 }! i8 v0 u3 `这似乎并不难理解,再进一步描述一下。
1 ]( A% b% j, `+ J看看下面这个函数声明:' a/ o2 J/ o$ J
+ [% G5 Z2 A! @* n) M/ cint fun(int x,int y);
1 Q0 P2 t6 }5 h2 O* `9 Z% M2 A/ h) d
这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。
7 k0 }1 I9 b: H接着看下面这个函数声明:
8 ~9 _7 q* I) b. E' q+ W9 i9 D3 G6 n7 Z) O1 L0 O! W2 G
int *fun(int x,int y);
% ` G: g: e% `7 N1 n3 Y/ S- F; D6 ]! Y" }; l( e
这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。- J% l+ @8 T5 E8 z* V
- }* ^1 e& ~" q. b2 T3 j7 a( y6 F/ n6 U4 S这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。0 I2 V4 [/ x1 }" a) k5 o
# ?) l( Y9 }) ]% @- m指针函数的写法8 Y% |2 h# ^8 S# X; B0 U
int *fun(int x,int y);
8 o9 x) V9 _6 ~3 T3 _, R( [# A, {int * fun(int x,int y);
' q: Q" \% i x, l3 S# I/ oint* fun(int x,int y);
+ i5 P8 C' ~ w
+ |6 _! F5 z: ^这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。; r* {8 _7 K5 m
7 `7 w7 r5 S# D: ~9 t1 n
示例
x7 n& @; e4 V) M+ `* [(由于本人习惯于 Qt 中进行开发,所以这里为了方便,示例是在 Qt 工程中写的,其语法是一样的,只是输出方式不同)4 W& R, z1 t! N' U# a$ F
来看一个非常简单的示例:
# h1 f" m4 |! u4 I+ J& P# h# R- `' @, L) y
typedef struct _Data{
/ @: L" e* Y9 ?- v8 [: c+ [5 h9 i int a;) b9 x8 z+ Q0 o0 P6 \4 |# B
int b;
/ ~# f9 \9 g. K% `}Data;1 O$ B7 t4 L4 P( `( `
, l+ c" R+ N$ r" Z/ n$ i//指针函数( L, \* f6 e( J- L* Y, X
Data* f(int a,int b){' ?) u% @8 Q4 x/ E
Data * data = new Data;
9 v& W! C* v! U7 W s1 |9 Y data->a = a;
' L) F" I4 f' Z: J+ V, v/ p4 k data->b = b;
( K( b1 s1 ?2 O6 F7 g return data;
^+ u" s+ f% l$ J H% n T}2 R8 Y" O" o( u t# _) b1 O
* v! \3 L% @2 O8 f, H+ f6 @
int main(int argc, char *argv[])
! z" D# Q1 t1 x. |' E{" y, D2 A( i l5 R$ W+ E
QApplication a(argc, argv);: P1 A+ M: \* O3 {8 m
//调用指针函数9 h3 {9 L3 `% S% }3 G
Data * myData = f(4,5);
) }! k- h/ l* D2 b qDebug() << "f(4,5) = " << myData->a << myData->b;
! X8 E7 O- i# N
, b+ ]9 i$ d/ Q7 P/ ]# Q return a.exec();. m( E, y. q5 F( [9 o3 {$ `. u
}- |& ^. z* l% t0 n- @
+ N4 P, g. ^. M
其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。: Z- D& l* J% L: @# l$ _6 }
7 U/ U0 k+ Y' R; q
函数指针$ Q7 R7 K* ~/ d: W, p2 h7 h
定义8 ~. M* p. H6 A- u# x
函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。( Z) @" U7 t' j. h7 @: n% m
声明格式:类型说明符 (*函数名) (参数)
8 b* q, @. O4 r' _# G$ Y- C如下:
1 ^# _% w$ T2 l/ v
}: h1 O5 E( d1 Sint (*fun)(int x,int y);
' Z* ^$ v# G7 A/ N9 K) k% n# f- v& J9 k# [7 }% V* _" x: b$ j
函数指针是需要把一个函数的地址赋值给它,有两种写法:
- o8 m$ r+ ]8 p3 D) I6 M! v7 k! E+ g/ b6 i2 r
fun = &Function;5 n% J% X. \) |; j, b5 F
fun = Function;7 B- T' M, j$ V$ @9 k! V3 v4 c
3 H+ S, H/ B$ w
取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
. h3 A4 Q& e7 u' F
, e% d0 j, a7 s3 C6 x9 F调用函数指针的方式也有两种:5 F8 U4 e+ W4 ]6 B2 J
+ F5 W6 Z; n- n( l" L3 R5 B0 m2 }x = (*fun)();
' X) y% n7 R1 D5 Wx = fun();5 i0 L7 y8 a( H) u5 M
1 ~. a: M& `; R9 A6 u
两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。, J2 Y9 F, O1 ~, L3 {0 \$ n
9 I! [% |# h8 K* |; {, i* I
示例
" E3 n2 }7 w! Bint add(int x,int y){
' Z& b9 d" ~* Z( u9 }* G. B( f& V) N return x+y;
* v) r: U, F: m s& h}
1 s, }! |6 L: b9 j: ]int sub(int x,int y){# @. c$ U6 i" r# P
return x-y;
- k Q- G# z* g! p" H7 g# p5 {! J}( b9 x/ V6 p' G4 |' g, ~) _
//函数指针
3 X7 Q, ~: C9 s8 [7 K! X# q/ N# rint (*fun)(int x,int y);; ^; Z+ \$ I2 T
' X' O& p- M ^( c- E ?2 Eint main(int argc, char *argv[])6 r$ H/ S2 Y$ Q- ^
{
% I8 r9 h8 f6 K/ M$ Y QApplication a(argc, argv);' p6 e9 W0 P" _+ r/ [/ C9 U# E
//第一种写法: E( W5 K4 r$ x1 ~
fun = add;0 R0 |0 y$ D) @+ M) x
qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ;
Y8 F5 a& L/ H! c9 J' n7 M, l# A //第二种写法) U( D5 A9 J' j$ s4 h! S
fun = ⊂, i4 {! t3 k4 O( H1 c: `
qDebug() << "(*fun)(5,3) = " << (*fun)(5,3) << fun(5,3);( F; `( ^* [* H C
9 H! j$ e- o* q( ^
return a.exec();
9 O) x: ~# M# j}
: ]6 ~+ ^6 E0 B4 }) b
, J6 Y# P# ]' _# t
0 q6 M/ `2 u: c2 v输出如下:0 a0 S0 L9 V. S
$ k2 r7 Y5 q! ?
(*fun)(1,2) = 3# x, p$ e+ U6 `- q
(*fun)(5,2) = 2 2$ w7 T- z( X6 d2 A
- r- F2 V; J' I1 \
上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。8 ?. S- o1 [0 ^
2 w" b7 j: K$ r- x E$ b x
二者区别4 E3 P( o0 `% F2 ]3 E
通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:
+ K) y% C( k0 A- d1 v/ _* a9 r+ F1 Y, [, o* s
定义不同! x4 Z* N6 [% T* {# d& X
指针函数本质是一个函数,其返回值为指针。
# T# x: ?1 t- z5 ^函数指针本质是一个指针,其指向一个函数。# O7 S/ G; q# n+ |
- G, J7 q+ x" @- @- ~& n, r8 G( L写法不同; P) @5 I. x9 m9 ~3 D0 N- e
指针函数:int* fun(int x,int y);/ _+ F/ Y" Q$ @$ |6 {# S L
函数指针:int (*fun)(int x,int y);2 I- W8 t+ N O, y- S
可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。( }1 _: w% j* K4 z& ^; S. S
再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。 S& i$ N( y" f; H3 f+ A
) x9 i% C7 B1 e, M3 j; X用法不同% |) S6 {8 s# J" ?
上面已经写了详细示例,这里就不在啰嗦了。
1 |" a. \. Q: t8 c1 }
$ V( {: }5 {2 g: @总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。5 g. \ N/ b8 O
! g/ J* S; t5 P. l3 y
8 Z) a- ]3 [" u* f$ ~, M
|
|