0%

C语言函数指针

函数指针是指向函数的指针变量,它可以像一般函数一样,用于调用函数、传递参数。

一、概念

      函数是计算机程序中一段可执行代码的封装,当程序运行时函数会被加载到内存布局中的代码段位置,这段代码会有一段内存空间,有内存空间就会有地址,这段内存空间的首地址就是函数的地址。一个变量的内存首地址可以存储在相应的指针变量中,同样的,函数的首地址也以存储在某个函数指针变量中,此时可以通过这个函数指针变量来调用所指向的函数。

声明方式:typedef int (*fun_ptr)(int,int);,即声明一个指向同样参数、返回值的函数指针类型。

函数指针和函数本身不可重名。

二、使用

  1. 函数名及取函数地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

void (*ptrFunc1)();

void (*ptrFunc2)();

void func() {
printf("hello,func:·\n");
}

int main() {
func();

ptrFunc1 = &func;
ptrFunc2 = func;

printf("%p -- %p\n", func, &func);
printf("%p -- %p\n", ptrFunc1, &ptrFunc1);
printf("%p -- %p\n", ptrFunc2, &ptrFunc2);
}
  • 运行得到结果:

    1
    2
    3
    4
    hello,func:·
    0x10ea01ed0 -- 0x10ea01ed0
    0x10ea01ed0 -- 0x10ea03010
    0x10ea01ed0 -- 0x10ea03018
  • 函数名funcptrFunc1ptrFunc2函数指针都是函数指针

    • func函数名是一个函数指针常量,而ptrFunc1ptrFunc2是函数数指针变量。
  • 取地址运算法&要求其操作对象是一个对象,但函数名不是对象(函数本身是一个对象),按照要求&func是非法的,但编译器允许这么做,c/c++标准的制定者也承认了其合法性。

  • func是函数的首地址,而&func表示一个指向函数func这个对象的地址。

  1. 多种用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void (*funP)(int);

void (*funA)(int);

void myFun(int x);

int main() {
printf("默认调用,");
myFun(100);
printf("*myFun调用,");
(*myFun)(100);
printf("&myFun调用,");
(&myFun)(100); // 等价于funP(100)

printf("funP调用,");
funP = &myFun;
(*funP)(200);
printf("*funP调用,");
funP(200);

printf("funA调用,");
funA = myFun;
funA(300);
printf("*funA调用,");
(*funA)(300);

return 0;
}

void myFun(int x) {
printf("myFun: %d\n",x);
}
  • 运行得到结果:

    1
    2
    3
    4
    5
    6
    7
    默认调用,myFun: 100
    *myFun调用,myFun: 100
    &myFun调用,myFun: 100
    funP调用,myFun: 200
    *funP调用,myFun: 200
    funA调用,myFun: 300
    *funA调用,myFun: 300
  • myFun的函数名与funPfunA函数指针一样,都是函数指针。

    • myFun函数名是一个函数指针常量
    • funPfunA是函数指针变量
  • 函数名调用如果都得如(*myFun)(10)这样,书写与读起来都是不方便和不习惯,所以C语言的设计者们才会设计成又可允许myFun(10)这种形式地调用。

    • 为了统一调用方式,funP函数指针变量也可以funP(10)的形式来调用。
  • 赋值时,可以写成funP=&myFun形式,也可以写成funP=myFun

  • 声明时,void myFun(int)不能写成void (*myFun)(int)形式,void (*funP)(int)也不能写成void funP(int)形式。

  1. 函数指针常量与函数指针变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <stdlib.h>

void (*funP)(int);
void (*funA)(int);
void myFun(int x);
int main() {
funP = &myFun;
funA = myFun;

printf("sizeof(myFun)=%d\n", sizeof(myFun));
printf("sizeof(funP)=%d\n", sizeof(funP));
printf("sizeof(funA)=%d\n", sizeof(funA));

printf("myFun:%p, &myFun:%p\n", myFun, &myFun);
printf("funP:%p, &funP:0x%p\n", funP, &funP);
printf("funA:%p, &funA:%p\n", funA, &funA);
return 0;
}

void myFun(int x) {
printf("myFun: %d\n",x);
}
  • 运行得到结果:

    1
    2
    3
    4
    5
    6
    sizeof(myFun)=1
    sizeof(funP)=8
    sizeof(funA)=8
    myFun:0x108f23ef0, &myFun:0x108f23ef0
    funP:0x108f23ef0, &funP:0x0x108f25018
    funA:0x108f23ef0, &funA:0x108f25010
  • 函数指针变量跟普通的指针一样在64位系统下大小都为4,函数指针常量的大小为1。

  • 函数指针变量和函数指针常量存储在内存的不同位置。

  1. 函数指针作为参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <stdlib.h>

typedef void(*FunType)(int); //前面加一个typedef关键字,这样就定义一个名为FunType函数指针类型,而不是一个FunType变量,/形式同typedef int* PINT;

void myFun(int x);
void hisFun(int x);
void herFun(int x);
void callFun(FunType fp,int x);

int main() {
callFun(myFun,100);//传入函数指针常量,作为回调函数
callFun(hisFun,200);
callFun(herFun,300);

return 0;
}

void callFun(FunType fp, int x) {
fp(x);//通过fp的指针执行传递进来的函数,注意fp所指的函数有一个参数
}

void myFun(int x) {
printf("myFun: %d\n",x);
}

void hisFun(int x) {
printf("hisFun: %d\n",x);
}

void herFun(int x) {
printf("herFun: %d\n",x);
}
  • 运行得到结果:

    1
    2
    3
    myFun: 100
    hisFun: 200
    herFun: 300

三、参考

  1. 参考一
  2. 参考二