|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
前言; N' n& O6 X- z4 F8 u
函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。0 p3 k0 Z9 s$ f3 K! p6 _/ k' I
今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。( w/ T; ]$ G# {& t+ R" m3 [, f! _
6 J: T( M9 F! i5 l
正文
0 {. x% ~3 o- g7 R; M2 q先来看看两者的定义以及说明。
) }5 }% A5 G" k0 O
' s6 c$ q- a7 K" v! G指针函数) q" x. s4 n6 _
定义
# n# P# \6 |4 _' R i7 M1 Z9 E指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。# k1 Z- q0 f" u% L- {4 {4 Z$ n
声明格式为:*类型标识符 函数名(参数表)- u" K( G8 Q; n3 f: `7 f- F
- U, t& j9 v; d这似乎并不难理解,再进一步描述一下。
, L# n- c& l4 ]! {9 @2 X: A看看下面这个函数声明:
; W6 n: m' Q+ j+ R* N# n
$ R. h: p. ~7 M1 c4 Qint fun(int x,int y);- P+ T6 @3 n- [+ y8 B) v
8 A" n5 A5 g% r v2 f; S- z/ ~这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。
9 D7 `8 G$ m6 }4 J. P7 |) ?$ e& N接着看下面这个函数声明: G- N$ C6 k$ Y- w
( B: d6 l/ ~4 S" Z! r" Z( bint *fun(int x,int y);( a( e9 V3 F! S8 B0 Q5 \
0 @5 {- s* x4 {4 f$ {/ w ?
这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。
. X3 b0 `8 V6 ~' I3 ~
R! U2 y. P9 A这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。
- b3 c" ?% u! G" C, I
+ }1 o& `1 M, e4 B5 Z5 t! U. }指针函数的写法
9 P& x* p4 n8 k: lint *fun(int x,int y);
0 A4 J) q2 }6 fint * fun(int x,int y);# J. R) u2 ~. x8 \
int* fun(int x,int y);; P+ _* a. \2 y0 e/ l. J4 b0 z; \
W" w0 I1 |: |; f这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。
9 t; T2 Z5 T9 `+ m( @; E+ R0 }7 g! a8 d# \5 b- M" \9 @" c% x7 S
示例9 D2 W4 n0 U0 c+ m' H" V9 C
(由于本人习惯于 Qt 中进行开发,所以这里为了方便,示例是在 Qt 工程中写的,其语法是一样的,只是输出方式不同)
, w) u# v8 e2 ^; M, z; K来看一个非常简单的示例:
" y+ o4 M$ @( ]3 I5 {9 a. ~; Y a* ~1 J. b- ]; T4 B* Z
typedef struct _Data{$ ], w6 E1 B1 s
int a;* ]* v; q1 [9 _
int b;/ o% S0 S( Z/ L. o/ g8 L2 a5 t# |
}Data;
$ ]. N4 t' z+ ^) [
! [) [# _/ S$ P# B//指针函数
: H$ |& g4 v# R+ B5 p& J4 W4 n/ GData* f(int a,int b){
1 o2 z: R" g$ B* Z) v0 O8 ~; R; s6 u" ^ Data * data = new Data;
+ ^& m# r8 o* `2 u' F1 Y data->a = a;: Q) a& Y+ D, P& C& ^
data->b = b;+ l1 o' x* r8 A, y! Q
return data;
# B4 ~6 a) B6 v: G# N" @, z}( `: J8 _$ l% B
' r- t; M. y: P- ?1 w& ]
int main(int argc, char *argv[])( E: k" j" k/ r
{9 H" @+ J) R' {/ a6 M
QApplication a(argc, argv);
" R# R2 h( ]* `: m/ R* r5 M //调用指针函数
( B, d# C4 k; h+ g' B0 M Data * myData = f(4,5);' \6 g Y8 \9 n# d
qDebug() << "f(4,5) = " << myData->a << myData->b;4 `2 b. V& M* _ {# i
$ Q5 L# u& u9 y/ G return a.exec();
0 C* e3 L: q2 q, b}
! N( x& s9 H% J7 G- ]2 U8 e% D) L# _# b9 C' s/ X( R5 b
其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。
- k9 ?9 V h; p- K. B7 @, A" F) e
- {: G5 }- x# g0 U; z4 o u/ P* b+ ^& R! P函数指针" k. O, _ W" Z' C6 ]8 \
定义% i5 Z# |, W( N7 M v$ z" D
函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。$ E- v* l* j* m
声明格式:类型说明符 (*函数名) (参数)
+ n" x9 B( j; n如下:5 u8 W6 p' {! [' D ~) W+ A5 b
/ o. A8 J+ Z1 S( ]int (*fun)(int x,int y);
% U# o5 T7 X9 t( T# }) p5 l: \! m L" a* c7 Z, E
函数指针是需要把一个函数的地址赋值给它,有两种写法:
+ } ?4 Y8 v4 Y* }7 v+ D' S
# I) R) Y; X/ S$ Gfun = &Function; {3 ^. r- {/ n( F
fun = Function;1 R7 H8 y Q7 v, f. P" s
2 C' E! a; S M2 b6 N4 m+ Z
取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
+ T$ s' A- A2 J3 N! X- i, r
5 N1 K: }. U4 _9 }调用函数指针的方式也有两种:
' K' Y( T+ P( u8 U6 z) |$ x2 p& t# v, Y9 Q# |) o
x = (*fun)();1 Z6 X) g' W+ W: j; ?, d8 e6 k2 n
x = fun(); _2 a4 }( ]+ u0 E2 z
1 e0 f* w* H- B+ M8 m& T8 e两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。
" G5 Q3 D4 C0 a3 x$ d
1 n! d6 T0 ?5 r4 `示例
# W8 P; y/ U P% \7 k: ^4 eint add(int x,int y){
7 j' T$ e0 u2 Q4 } return x+y;
8 N, P8 ]3 m! s}% X. O; r% c. R* n `+ y. o( }0 d4 @4 b
int sub(int x,int y){4 m' f: [5 c- ?+ f5 _5 M
return x-y;( R7 N8 g( i' \- F) M6 Y* Q! ~
}
" r2 n( e) T7 M( B//函数指针" h: C7 e$ U3 r" {$ n
int (*fun)(int x,int y);4 b; v( X* Y% L; n/ j- g( ]
, X/ }% Y% Z7 z: Eint main(int argc, char *argv[])0 H/ D: ^$ H, ?* |7 A( v9 L
{
- ]% H" d9 N& a3 R5 j& a QApplication a(argc, argv);. k" F& z- s9 \
//第一种写法0 u- F7 g/ t6 b* w2 @; c
fun = add;
" P: ~: y/ ]0 d$ y9 x qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ;6 o. r* j6 _5 D) m0 D
//第二种写法
/ j/ A9 E) e& D: t0 t, s$ _ fun = ⊂
, f3 g( M/ E$ |" p- T$ I P qDebug() << "(*fun)(5,3) = " << (*fun)(5,3) << fun(5,3);
' A; z g2 {. k, `' T) J, J8 w H/ V# [7 Y$ I( [8 _
return a.exec();
* I1 H/ ?9 m/ }2 e2 o) `8 a2 ^}6 b2 o% W2 R. X* s: g
- m, ?( l4 t+ T; K# m/ O; ^2 R+ D" g- K/ I: t+ h `
输出如下:, k6 `3 s D% ^( e0 K% U, @7 C) h. ?2 J8 y
. w+ n0 k2 K$ Z, d- j
(*fun)(1,2) = 3
8 _* F v% n0 z) i( O(*fun)(5,2) = 2 2
. P6 u- H" Z4 {5 d) }4 t A. G9 x+ c8 E
上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。
5 H% t. n" |# [5 r7 n
8 F- y4 d$ I% K. |二者区别8 h# b' o) S: a; X. b- s8 W9 L+ \
通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:
+ }6 Q; M c/ P* j; `" S% `+ s6 A5 x8 u
定义不同
0 m* k' [$ |" n/ `; G指针函数本质是一个函数,其返回值为指针。1 _( A6 X! e, r; _
函数指针本质是一个指针,其指向一个函数。
( X- B: q* r( z: y( D% J) d: v$ n- b/ d# W0 S
写法不同
' _! [; n) X. u, ~指针函数:int* fun(int x,int y);
; ~7 a) o: t3 ]4 G+ o2 g函数指针:int (*fun)(int x,int y);
% _+ H. `2 W8 b" n0 k. ?可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。
; l8 i% T6 z: @+ ^) R/ m再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。
! s! j4 B4 T3 W& F* {7 X0 [
6 m9 N$ F3 o7 Z% W% m. |用法不同- f5 e* p. Z9 H3 I. g
上面已经写了详细示例,这里就不在啰嗦了。
$ j$ q/ l7 Z. [; E6 O2 i' i2 Z, u7 K1 R( f1 }3 b3 c V8 B* l
总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。
8 y, `; u) U, _3 h) U
, X) O4 p: a1 r/ X, e; e! }/ Q# V3 M/ Q$ Y8 ^$ h
|
|