找回密码
 注册
查看: 272|回复: 2
打印 上一主题 下一主题

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
前言
" t* k5 j% M- ~% ?' i, o函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。/ o, v0 H1 ^8 p+ p
今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。
% r4 S9 `6 k! E5 C$ O% K4 Q
* C5 p, {: |" [正文! A  \" `9 }: D% R+ k
先来看看两者的定义以及说明。
. _, V# r0 k. B" m2 e1 c( R7 h
: r9 U$ p+ Q. X# a. _7 c+ H( f指针函数
! T  n1 h( p4 A定义  J/ C. Z& V2 ~# z- q- Z$ E
指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。
  M% ^, O6 o! H7 J9 t; k声明格式为:*类型标识符 函数名(参数表)0 Z0 D2 E: p' v+ u  n

" u# {1 J9 \" J# O! u& u, M4 E8 K; I这似乎并不难理解,再进一步描述一下。
" j! Q- E: [9 S) Q6 O看看下面这个函数声明:
* ^* k8 F! ~* ]/ |; t) W
- \' N$ o# w. N8 ~int fun(int x,int y);
! }4 i6 \: X0 G7 |7 Y& x1 {9 C- t2 H- p3 q* K
这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。8 x0 @. F  g! G/ H
接着看下面这个函数声明:
- N0 K" N5 ]( j, k1 `; i" _- |9 v; m8 ]  v# g0 q( |- Q, L" N
int *fun(int x,int y);
1 r( m- x- o. w' I/ X7 h
: ^( e1 d$ u/ G8 _* e这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。
  S8 m: t' f# M7 c% _1 O/ N" p7 ]' I  r; d9 y7 A- H4 Y/ I
这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。
0 V2 A2 C* V4 ]; o
# L8 `9 ~# s& {4 `3 A3 n指针函数的写法$ P$ q6 Y6 x9 M: U/ a& w' S% b
int *fun(int x,int y);( R1 S2 P3 i# k' m1 U9 s
int * fun(int x,int y);' F0 [: F) b' [* T  k: B& d/ ~2 Y
int* fun(int x,int y);
0 Q# y! s( W7 y% w/ @% h9 ]& C; v' V6 P# u- Z: J; x& b
这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。+ V5 t. P. V7 L: I
7 W, \; ?7 B4 U/ z8 W
示例
& z- @7 r. F0 G" I(由于本人习惯于 Qt 中进行开发,所以这里为了方便,示例是在 Qt 工程中写的,其语法是一样的,只是输出方式不同)
9 d  j! ?) j: M* P来看一个非常简单的示例:
5 b" K: u* Q5 [4 d6 [  Q& D9 U6 C1 B; e' o5 b1 U" v" Z
typedef struct _Data{9 T8 |5 @8 M5 x  r
    int a;
; Y3 V9 [% X* j9 P; P) M: j    int b;
' R1 Y3 T& {% O: C5 Y/ L}Data;* m0 B3 u$ F/ {9 I+ d1 M8 \6 \
0 ?. B2 E6 O6 A) r  f4 B8 o
//指针函数
* N5 ^+ q% y; N1 uData* f(int a,int b){) w# ?3 ?: G, |) Q. N- A: O& \
    Data * data = new Data;
  M$ {, S  V) k( R, h0 I. a    data->a = a;
# ?6 x& x8 d5 E) i# \0 ?* x/ s    data->b = b;
1 T/ u6 ^+ s2 G  ^    return data;5 ^1 w0 t6 ~  K0 }2 P3 o
}
  q: x. F. O) b
& y5 p0 j& f% C+ C9 X. n9 ^int main(int argc, char *argv[])
" s+ R& [9 a& F; w( h7 L{* \3 t% n; P- O, Y& F3 K
    QApplication a(argc, argv);5 v; a: T- k- q! S
    //调用指针函数
0 ^" m! {$ P# `: q5 k    Data * myData = f(4,5);9 b0 V3 J& X! ~; T
    qDebug() << "f(4,5) = " << myData->a << myData->b;) e8 H0 y; `1 `7 `  M5 a
8 S/ ?6 ?, S! q  F) _
    return a.exec();, g; V( c- J; ]3 T8 ]
}$ B$ G* u) y( W7 \8 ~

6 r) j# |3 x7 w3 N其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。
9 W+ ^0 l, S% F- u  h# L7 \# I% y3 u. D1 s2 `# G
函数指针
2 h9 r& E- V! X8 T+ s0 d定义
0 G9 f6 _( J' s% L9 c" A, I函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。
  i( L! [/ N2 [声明格式:类型说明符 (*函数名) (参数)
/ O$ l( }% B+ ~0 B: X6 X, _如下:
, |9 G; ^/ G1 F! |3 w
0 @$ ?  r5 N" o/ _1 Eint (*fun)(int x,int y);2 s3 x1 z% X$ E2 u, @
0 b- L- b1 K) J2 n8 F% ]8 ^
函数指针是需要把一个函数的地址赋值给它,有两种写法:/ L: i8 J1 c! D* C: r# E
5 R6 w  a; S% w
fun = &Function;* w( [2 ~' M0 u5 Q# j( ]& m
fun = Function;
( U! z/ }  _1 u) V6 }2 v1 z
9 i3 [3 m6 T% q, [1 k取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
: Z" G" R) b3 t' u
8 R) `+ N0 \+ w! e: d5 y调用函数指针的方式也有两种:
& J' e! s  {% a8 {& e2 S7 W) T! G
# T4 S0 E" m" s3 m0 K- hx = (*fun)();
7 g+ J, J2 i, F4 c/ S+ Px = fun();
# z8 i; ^' }7 [( f( V; K( _4 w" c
两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。
$ d3 e* }: r, [; W) N3 \7 ^+ F$ g$ b& S, v/ w
示例5 l# i8 G5 S- M; i- z
int add(int x,int y){
: m3 r* q0 A3 A; f: E6 E+ @- X: f' ?    return x+y;
5 @2 w# n+ Z2 d" q1 P8 ?}! v. j7 \- j. }
int sub(int x,int y){
* Q' V1 S) ^( F4 Z    return x-y;
5 d. [  K3 Z5 W/ j1 r+ }}& E9 ~7 M9 ]& ]
//函数指针
8 f4 q& ^. A: W3 t) nint (*fun)(int x,int y);
9 B0 F) q' U. x, s9 P
( ^  T  \% `  k2 |# E* Z( j+ x+ {int main(int argc, char *argv[])1 z) K4 ^& a) I& N$ Q/ e8 k: L: T+ Q
{
# y. S5 l  K% c. K    QApplication a(argc, argv);% F# A: L$ b' s2 D! ~
    //第一种写法
0 u2 J0 N  N1 D+ Q* `    fun = add;
* u2 e+ u3 F7 c1 n8 d9 U    qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ;" b# ]' V4 {4 V$ X+ \9 c6 O# n
        //第二种写法. X( R, F6 R$ ?* s+ o. m
    fun = &sub;
# ~. `1 Y: K5 \1 v* [5 M& _    qDebug() << "(*fun)(5,3) = " << (*fun)(5,3)  << fun(5,3);
6 }6 b8 G! t9 k' _# c* J( l% ^) ~/ o+ E
    return a.exec();
0 E- _) D* b5 ^. J0 B) K" Z$ v}
# P" R. Z( q4 @- ]9 {4 a3 ]' V3 U3 c6 ], S* \, V- S9 b2 v

. i' \, s3 H3 h! ^( _4 t输出如下:
' X% y& {* Y5 r0 R- ^5 R: r! Z3 g, B$ D# }7 k& D! I
(*fun)(1,2) =  3
' T. B" L0 t/ N(*fun)(5,2) =  2 2: |9 {# f9 L8 n' q( D

' M; ^; x% z; l( Y上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。
1 v, m$ ?0 [* v1 o/ m3 I3 U1 s3 h& P& h: m; L2 a# b5 H
二者区别
; d1 X% T- v4 v通过以上的介绍,应该都能清楚的理解其二者的定义。那么简单的总结下二者的区别:
9 G- Y. A8 M8 ?. ]2 {; v& u( A$ c, Q, t7 X
定义不同
" H( ]  A% }/ N# g# a. ?  N指针函数本质是一个函数,其返回值为指针。1 N4 y3 l! c! i. W( h2 a/ q
函数指针本质是一个指针,其指向一个函数。6 N0 p. U& q3 G! g% Y
1 ^% \7 ^4 Y" @3 s, K5 d4 O3 C7 I
写法不同
) Y2 Q% V+ ]1 ]0 {$ _: U指针函数:int* fun(int x,int y);
* q& n+ L- H  ^9 ?& v+ c- X! u4 g函数指针:int (*fun)(int x,int y);
9 J: ]$ b, k' \9 a' N2 g; \可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。% Q& v* E5 ^  \' U. K! |1 {
再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。
9 A0 _* t" E) U6 q. p- N
, V$ t8 |8 ]9 B$ b' G用法不同1 E/ M# n+ ?' `# V  t: v
上面已经写了详细示例,这里就不在啰嗦了。
8 m# ^# L$ a8 q9 \
" _5 {, y: l3 I4 G) q0 [9 i. n总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。
: R+ R- Y; z; F2 R# d
; ]# U0 M$ g, F! a; m1 M; v$ Z2 Z1 Z
# z. b9 h" h& R: e: o4 l# Z

该用户从未签到

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

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-5-24 21:46 , Processed in 0.078125 second(s), 23 queries , Gzip On.

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

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

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