一、指针函数
指针函数: 顾名思义,它的本质是一个函数,不过它的返回值是一个指针。其声明的形式如下所示:
ret *func(args, ...);
讯享网
其中,func是一个函数,args是形参列表,ret *作为一个整体,是 func函数的返回值,是一个指针的形式。
下面举一个具体的实例来做说明(文件:pointer_func.c):
讯享网# include <stdio.h> # include <stdlib.h> int * func_sum(int n) { if (n < 0) { printf("error:n must be > 0\n"); exit(-1); } static int sum = 0; int *p = ∑ for (int i = 0; i < n; i++) { sum += i; } return p; } int main(void) { int num = 0; printf("please input one number:"); scanf("%d", &num); int *p = func_sum(num); printf("sum:%d\n", *p); return 0; }
上例就是一个指针函数的例子,其中,int * func_sum(int n)就是一个指针函数, 其功能十分简单,是根据传入的参数n,来计算从0到n的所有自然数的和,其结果通过指针的形式返回给调用方。
以上代码的运行结果如下所示:
root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 12 drwxr-xr-x 2 root root 4096 Oct 26 22:16 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rw-r--r-- 1 root root 472 Oct 26 22:14 pointer_func.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# gcc pointer_func.c -o pointer_func root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 32 drwxr-xr-x 2 root root 4096 Oct 26 22:16 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rwxr-xr-x 1 root root 16960 Oct 26 22:16 pointer_func* -rw-r--r-- 1 root root 472 Oct 26 22:14 pointer_func.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ./pointer_func please input one number:3 sum:3 root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ./pointer_func please input one number:4 sum:6 root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study#
如果上述代码使用普通的局部变量来实现,也是可以的,如下所示(pointer_func2.c):
讯享网# include <stdio.h> # include <stdlib.h> int func_sum2(int n) { if (n < 0) { printf("error:n must be > 0\n"); exit(-1); } int sum = 0; int i = 0; for (i = 0; i < n; i++) { sum += i; } return sum; } int main(void) { int num = 0; printf("please input one number:"); scanf("%d", &num); int ret = func_sum2(num); printf("sum2:%d\n", ret); return 0; }
本案例中,func_sum2函数的功能与指针函数所实现的功能完全一样。
root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 36 drwxr-xr-x 2 root root 4096 Oct 26 22:19 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rw-r--r-- 1 root root 470 Oct 26 22:20 pointer_func2.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# gcc pointer_func2.c -o pointer_func2 root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 56 drwxr-xr-x 2 root root 4096 Oct 26 22:20 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rwxr-xr-x 1 root root 16928 Oct 26 22:20 pointer_func2* -rw-r--r-- 1 root root 470 Oct 26 22:20 pointer_func2.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ./pointer_func2 please input one number:4 sum2:6 root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study#
不过在使用指针函数时,需要注意一点,相信细心地读者已经发现了,对比func_sum和func_sum2函数,除了返回值不一样之外,还有一个不同的地方在于:
- 在func_sum中,变量sum使用的是静态局部变量,而func_sum2函数中,变量sum使用的则是普通的变量。
如果我们把指针函数的sum定义为普通的局部变量,会是什么结果呢?不妨来试验一下(pointer_func3.c):
讯享网# include <stdio.h> # include <stdlib.h> int * func_sum(int n) { if (n < 0) { printf("error:n must be > 0\n"); exit(-1); } int sum = 0; int *p = ∑ for (int i = 0; i < n; i++) { sum += i; } return p; } int main(void) { int num = 0; printf("please input one number:"); scanf("%d", &num); int *p = func_sum(num); printf("sum:%d\n", *p); return 0; }
root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 60 drwxr-xr-x 2 root root 4096 Oct 26 22:22 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rw-r--r-- 1 root root 465 Oct 26 22:23 pointer_func3.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# gcc pointer_func3.c -o pointer_func3 root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 80 drwxr-xr-x 2 root root 4096 Oct 26 22:23 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rwxr-xr-x 1 root root 16928 Oct 26 22:23 pointer_func3* -rw-r--r-- 1 root root 465 Oct 26 22:23 pointer_func3.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ./pointer_func3 please input one number:4 sum:6 root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study#
可是如果我们把main函数里面稍微改动一下(pointer_func4.c)::
讯享网# include <stdio.h> # include <stdlib.h> int * func_sum(int n) { if (n < 0) { printf("error:n must be > 0\n"); exit(-1); } int sum = 0; int *p = ∑ for (int i = 0; i < n; i++) { sum += i; } return p; } int main(void) { int num = 0; printf("please input one number:"); scanf("%d", &num); int *p = func_sum(num); printf("wait for a while...\n"); //此处加一句打印 printf("sum:%d\n", *p); return 0; }
我们在输出sum之前打印一句话,这时看到得到的结果完全不是我们预先想象的样子,得到的并不是我们想要的答案。
root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 84 drwxr-xr-x 2 root root 4096 Oct 26 22:25 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rw-r--r-- 1 root root 529 Oct 26 22:25 pointer_func4.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# gcc pointer_func4.c -o pointer_func4 root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ll total 104 drwxr-xr-x 2 root root 4096 Oct 26 22:26 ./ drwxr-xr-x 5 root root 4096 Oct 26 21:46 ../ -rwxr-xr-x 1 root root 16928 Oct 26 22:26 pointer_func4* -rw-r--r-- 1 root root 529 Oct 26 22:25 pointer_func4.c root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study# ./pointer_func4 please input one number:4 wait for a while... sum:- root@iZm5e9phbzdxx0lysrv9t2Z:/home/C_Study#
上面的示例中,在返回该指针后,立即访问,的确是得到了正确的结果,但这只是十分巧合的情况,如果我们等待一会儿再去访问该地址,很有可能该地址已经被其他的变量所占用,这时候得到的就不是我们想要的结果。甚至更严重的是,如果因此访问到了不可访问的内容,很有可能造成段错误等程序崩溃的情况。
因此,在使用指针函数的时候,一定要避免出现返回局部变量指针的情况。
那么为什么用了static就可以避免这个问题呢?
原因是一旦使用了static去修饰变量,那么该变量就变成了静态变量。而静态变量是存放在数据段的,它的生命周期存在于整个程序运行期间,只要程序没有结束,该变量就会一直存在,所以该指针就能一直访问到该变量。
二、函数指针
与指针函数不同,函数指针 的本质是一个指针,该指针的地址指向了一个函数,所以它是指向函数的指针。
我们知道,函数的定义是存在于代码段,因此,每个函数在代码段中,也有着自己的入口地址,函数指针就是指向代码段中函数入口地址的指针。
其声明形式如下所示:
讯享网ret (*p)(args, ...);
其中,ret为返回值,*p作为一个整体,代表的是指向该函数的指针,args为形参列表。其中p被称为函数指针变量。
1、关于函数指针的初始化
与数组类似,在数组中,数组名即代表着该数组的首地址,函数也是一样,函数名即是该数组的入口地址,因此,函数名就是该函数的函数指针。
因此,我们可以采用如下的初始化方式:
函数指针变量 = 函数名;
下面还是以一个简单的例子来具体说明一下函数指针的应用(func_pointer.c):
讯享网#include <stdio.h> int max(int a, int b) { return a > b ? a : b; } int main(void) { int (*p)(int, int); //函数指针的定义 //int (*p)(); //函数指针的另一种定义方式,不过不建议使用 //int (*p)(int a, int b); //也可以使用这种方式定义函数指针 p = max; //函数指针初始化 int ret = p(10, 15); //函数指针的调用 //int ret = (*max)(10,15); //int ret = (*p)(10,15); //以上两种写法与第一种写法是等价的,不过建议使用第一种方式 printf("max = %d \n", ret); return 0; }
上面这个函数的功能也十分简单,就是求两个数中较大的一个数。值得注意的是通过函数指针调用的方式。
首先代码里提供了3种函数指针定义的方式,这三种方式都是正确的,比较推荐第一种、第三种定义方式。然后对函数指针进行初始化,前面已经提到过了,直接将函数名赋值给函数指针变量名即可。
上述代码运行的结果如下:

调用的时候,既可以直接使用函数指针调用,也可以通过函数指针所指向的值去调用。(*p)所代表的就是函数指针所指向的值,也就是函数本身,这样调用自然不会有问题。有兴趣的同学可以去试一试。
2、为什么要使用函数指针?
那么,有不少人就觉得,本来很简单的函数调用,搞那么复杂干什么?其实在这样比较简单的代码实现中不容易看出来,当项目比较大,代码变得复杂了以后,函数指针就体现出了其优越性。
3、回调函数
函数指针的一个非常典型的应用就是回调函数。
什么是回调函数?:回调函数就是一个通过指针函数调用的函数。其将函数指针作为一个参数,传递给另一个函数。
回调函数并不是由实现方直接调用,而是在特定的事件或条件发生时由另外一方来调用的。
#include<stdio.h> #include<stdlib.h> //函数功能:实现累加求和 int func_sum(int n) { int sum = 0; if (n < 0) { printf("n must be > 0\n"); exit(-1); } for (int i = 0; i < n; i++) { sum += i; } return sum; } //这个函数是回调函数,其中第二个参数为一个函数指针,通过该函数指针来调用求和函数,并把结果返回给主调函数 int callback(int n, int (*p)(int)) { return p(n); } int main(void) { int n = 0; printf("please input number:"); scanf("%d", &n); printf("the sum from 0 to %d is %d\n", n, callback(n, func_sum)); //此处直接调用回调函数,而不是直接调用func_sum函数 return 0; }
上面这个简单的demo就是一个比较典型的回调函数的例子。在这个程序中,回调函数callback无需关心func_sum是怎么实现的,只需要去调用即可。
这样的好处就是,如果以后对求和函数有优化,比如新写了个func_sum2函数的实现,我们只需要在调用回调函数的地方将函数指针指向func_sum2即可,而无需去修改callback函数内部。
以上代码的输出结果如下:
回调函数广泛用于开发场景中,比如信号函数、线程函数等,都使用到了回调函数的知识。
指针函数和函数指针_chenyc4的博客-CSDN博客_函数指针和指针函数

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/129503.html