找回密码
 注册
关于网站域名变更的通知
查看: 306|回复: 2
打印 上一主题 下一主题

函数指针和指针函数用法和区别

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-11-26 13:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
前言/ P' @# `7 c+ S. D3 G% o- \
函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。
, D) G7 q" ~  p# G. U今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。
7 w9 c( D# m! }1 M& @0 ?
% w3 l+ Y0 m* c1 v0 z2 O' M正文8 T' _6 h, u! x( l; ?1 I
先来看看两者的定义以及说明。
9 X1 T/ j3 g/ V9 Q+ P
9 @5 E& v' @4 C9 _8 r指针函数
& G4 |6 x" y9 h定义
/ Y  f: e/ u/ ?6 X- y, X指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。$ ?0 Y2 O+ B2 W# e
声明格式为:*类型标识符 函数名(参数表)4 y& H$ \( h4 L- f

) f/ J- C: u5 u9 Q& Y1 [& f这似乎并不难理解,再进一步描述一下。  G* t5 Z6 U2 c8 X
看看下面这个函数声明:: I% Y8 g$ X1 _2 W. l! ]: A
9 j" D* `7 l2 E
int fun(int x,int y);/ A+ y& H: p% D5 n1 u' W( }
( @! u' w/ J& r6 {$ o9 }
这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。8 \. r" j0 I/ m) Y
接着看下面这个函数声明:( P/ L# H6 Q+ z, |+ U+ l; |

: o/ f1 O) R1 ~: f( W- M1 C+ Cint *fun(int x,int y);" ?  M+ o; }5 T
/ x0 ~& Y/ L% t
这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。5 V3 M+ h8 r- I+ v
+ r  b4 j/ O- k' e. ^
这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。
  P$ I+ l; ?9 ]. |; S* J& \" R" x( Q: l: B
指针函数的写法
) g+ w# R/ k3 E7 H" B. Q' rint *fun(int x,int y);
% z$ T8 X7 q0 C) h2 g( Hint * fun(int x,int y);
$ K+ X/ `! `$ g2 h1 L  s0 cint* fun(int x,int y);1 B1 P+ P# F2 V7 B+ V$ O

7 z2 |5 l1 m1 l" |9 x- j这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。
* m+ C4 A& z$ ~+ b! z+ _
6 d4 R' v& c2 n6 q/ L* q  ^- T示例- a0 q: O( k& }1 w! q
(由于本人习惯于 Qt 中进行开发,所以这里为了方便,示例是在 Qt 工程中写的,其语法是一样的,只是输出方式不同)  |3 _# C5 c  `6 e& s6 w2 ]- S
来看一个非常简单的示例:
) ^7 P( J, E+ |4 |" O
$ u& G/ R! t+ l- I) ltypedef struct _Data{9 s% H  Z. z% \3 l' W. L8 g
    int a;+ N2 m3 h& w. G/ b+ \  f
    int b;
: k! t" Z' T2 Y}Data;+ f# ]6 {* v6 h' f6 N

. Y0 E7 Q6 L+ t, F! ^+ T, w//指针函数
- s1 I, g! ?. B/ k9 V/ A* f6 dData* f(int a,int b){1 X# ~0 s4 h) o' G
    Data * data = new Data;
: Q. g) ^9 O5 O5 N/ H7 B7 }    data->a = a;/ e5 V' ]3 b/ ]3 B8 r3 c$ G6 O
    data->b = b;
, l' [  T3 K& r% g    return data;; p; D# n. f6 a) ^
}# D  q2 w+ u* X* q9 L) M2 T8 E( {$ @
% Q" A2 K' D. o0 e
int main(int argc, char *argv[]). h' j8 n9 z0 R- R/ D
{
+ g- A4 \6 |' _  R, s% n" p    QApplication a(argc, argv);4 ?% C, b3 Z; n* v- Q' j
    //调用指针函数
. O' m' {# e/ |6 A9 h/ @' f0 h    Data * myData = f(4,5);7 X3 z# h: G$ @1 B3 h) Y9 h: b
    qDebug() << "f(4,5) = " << myData->a << myData->b;
% Z7 S. d+ }- G) C9 z% J6 y4 S( A, ~5 W
    return a.exec();% K. j1 }$ k4 ~0 q6 y9 Q
}( x% w; [4 H, L7 k" P( ]

, V$ b$ h0 y0 y  \' b6 L: Y3 Q其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。
+ m6 s5 n  c' y2 L, {! s; W( `$ g' i% w" `% P" t
函数指针- ~4 ^. d, o8 W" h5 b$ C* ^
定义
* y) }6 }6 S. z# g5 K$ n/ a函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。  E* |' G5 g7 u' E8 ?1 K
声明格式:类型说明符 (*函数名) (参数)0 }3 L0 F3 O8 u& H" [# I( V
如下:
; C+ ~% u; B( \6 }( K! K; A/ l
7 s+ U  C2 h* ^  Vint (*fun)(int x,int y);! o; X# h/ j8 r2 j( S1 w& F& _& |; f
* w; H- D8 w' @! E
函数指针是需要把一个函数的地址赋值给它,有两种写法:2 L3 p* T( Q. B

& e. d2 X' U6 Q; G9 z/ N" kfun = &Function;
5 I1 e# ?9 S/ a& e9 U+ Efun = Function;
5 q6 C' \3 v" \- y7 l5 Y. C+ e  F. w5 c; ^3 e
取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
+ V8 J: {( G1 q/ p2 r$ i1 s$ v3 A; S: L, o5 p; D. Z
调用函数指针的方式也有两种:; S9 C- I) r) X7 W+ I) ?

. h6 O5 w( J/ m9 C9 ?6 t3 c, Px = (*fun)();' A* A: d% _- a& u/ I. Z  c; F
x = fun();
4 q% H! W) D4 n* ]3 }
' G6 a- m* C0 B. K两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。% I' S$ C; v* p$ m" Z# E9 Q* n

8 @2 Q3 A% q0 M! Q; X1 L* M3 ]+ h示例$ J1 x4 Z+ z: v. _' r6 I% Z4 U5 S
int add(int x,int y){
4 G( ?% I* x- i, `! ~9 [3 ]    return x+y;
+ o! N; p. z! k% ]" r1 T}
- A/ u: i& b; K6 `! d7 b& V% uint sub(int x,int y){/ A/ x5 Z, `: }! E$ _: B+ k7 d. ]
    return x-y;+ ~6 c7 a$ J; d
}% T; q1 m; O; X" r
//函数指针; n/ l$ J# l% c$ N9 ?  m1 u# o7 E! \8 O
int (*fun)(int x,int y);
, U0 l- a! L' }. q/ v
+ u. C) C; h& g" L' [2 H2 M# aint main(int argc, char *argv[])9 Q, W2 D) f# M. j) r, ?( p0 u; q1 @
{
9 Z& ^1 ]; z. i, A& T3 D7 w* x' n    QApplication a(argc, argv);; y; d+ q3 t7 i# d% E
    //第一种写法& h0 G2 }8 U( S, _4 K2 m/ @/ b
    fun = add;" `2 @9 }: ^# N; A" S6 n* Y
    qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ;
1 F7 d$ d! N* J$ B  |! V        //第二种写法+ [, w: ~. v; T: {
    fun = &sub;
9 }4 g, T! A7 A5 T    qDebug() << "(*fun)(5,3) = " << (*fun)(5,3)  << fun(5,3);
0 r/ I( Q) |6 ^/ D' m# ]) _+ d( B: S* D2 _4 J
    return a.exec();
# @* O% U+ r" o+ X3 h" V}
6 W  P; t. k; E# z: c  T- n
$ v6 g$ ]( T5 Q$ x$ t4 J0 j! @  g, p' O% `0 ~. N& W: T
输出如下:& L- E7 `$ C: I, i* C3 D, A, r( o
$ G/ ]! e, s" o* Y* U8 d
(*fun)(1,2) =  3* X2 x/ ~- F0 Z. b$ U" l. D% J: ^
(*fun)(5,2) =  2 2
& v4 e# M+ e8 G$ Z4 j+ Q5 [# N* A- s
上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。" ]# m2 r3 n" d
  N  ]" v5 s2 M+ t: |" z
二者区别! D; w3 _0 k" v  b3 ]2 E$ M6 P
通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:
2 h( v9 {0 f0 @' A1 p
3 J8 K+ A- f9 j; c; U定义不同0 G. g7 p8 ?# _9 F- X! r7 s
指针函数本质是一个函数,其返回值为指针。2 A" k( N$ D; B+ E  Y
函数指针本质是一个指针,其指向一个函数。
7 x1 H0 ~. G# v2 p# y0 K; p- v8 b2 s2 R+ \+ n. S* i& Z
写法不同3 y* S/ G4 q7 B" g5 a) Q
指针函数:int* fun(int x,int y);
  D( C( ]$ ], Q3 l5 |函数指针:int (*fun)(int x,int y);
/ b+ x) O* x! e1 n( C, D  p可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。
) V4 d- N4 u6 j+ U3 c& o再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。* \5 o0 F; }% y; W$ i- J5 f
/ k  L- X" b1 q% P- L' V8 m* D( s6 A
用法不同$ o9 d# V2 |7 J& U
上面已经写了详细示例,这里就不在啰嗦了。
' f* {5 w- [! q. X( I! ~% S- V- N* y6 u* G, \8 }9 O
总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。
! Z& }' e7 M7 o
4 S; v8 \5 P5 P/ x- Q1 U8 U% r3 V% S

该用户从未签到

2#
发表于 2021-11-26 15:06 | 只看该作者
指针函数,简单的来说,就是一个返回指针的函数

该用户从未签到

3#
发表于 2021-11-26 16:09 | 只看该作者
函数指针,其本质是一个指针变量,该指针指向这个函数
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-10-6 23:18 , Processed in 0.109375 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表