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

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

[复制链接]

该用户从未签到

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

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 = &sub;
' 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

该用户从未签到

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

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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