C语言指针详解(函数指针)

C语言指针详解(函数指针)函数指针说白了也是一个指针 指针中所保存的地址中的内容是一个函数 同之前说过的数组指针相似 函数指针的定义便是返回类型 指针名 函数参数 例如 int pa intx iny 同

大家好,欢迎来到IT知识分享网。

一.函数指针

1.1函数的定义

在讨论函数指针的定义之前,我们同样先看函数是怎么样定义的:

C语言指针详解(函数指针)

如上图所示,函数是由三个部分组成,分别为

  • 函数名 + ( )   (括号证明这是一个函数)
  • 函数参数 int x和int y
  • 函数的返回类型  int

而调用函数时需要函数名+ (对应的参数)即可,如上图的Add(a,b)

1.2函数指针的定义

函数指针说白了也是一个指针,指针中所保存的地址中的内容是一个函数,同之前说过的数组指针相似,函数指针的定义便是

返回类型  (* 指针名) (函数参数)   //例如: int (*pa) (intx,iny)

同数组指针一样,当定义函数指针的时候,* 需要和指针名打括号相结合,( )的优先级高于 * ,不打括号编译器自动会将 指针名 与( )相结合,如 int * pa (int x,int y) ,这样的话便是一个名为pa的函数,函数参数为 int x,int y,函数的返回类型时 int *

1.3示例

示例1:

(*(void (*)())0)();

请问:该代码是什么意思? 

分析:我们先将左右两边的括号一个一个匹配,变成如下:

C语言指针详解(函数指针)
相同颜色为一组括号

然后再从内到外逐层拆解

  1. 先看 void ( * ) ( )  ,这是一个标准的函数指针,函数返回类型为void,无函数参数
  2. 再看蓝色括号,该括号的代表强制转换,例如:(float)3 指的是将int类型的3转换为float类型,在这里指的是将int类型的0转换为函数指针类型
  3. 看蓝色括号前面的 * ,这里是解地址符,指找到地址是0的函数
  4. 红色的括号包括着地址是0的这个函数(函数指针此时是0),后面再跟着一个绿色的括号,相当于调用函数

所以该代码是一次函数调用,调用的是一个返回类型为void,无函数参数,函数名为0 的一个函数

1.3函数指针的调用 

我们先来看一个有意思的情况:

C语言指针详解(函数指针)如上图,当尝试打印Add函数的地址和Add这个函数变量名时,会发现Add变量名就是函数的地址,相当于我们平时在调用函数时就是在通过类似指针调用

所有我们的函数调用就可以用如下方式来进行:

C语言指针详解(函数指针)

如上图:

Add(a,b)的效果等同于(*p)(a,b) 

那么有一个新的问题:如果函数名就等同于函数指针,那直接用函数名不就可以了吗,为什么还需要函数指针?

二.回调函数

回调函数就是函数指针最佳的使用方式

1.1回调函数的定义

所谓的回调函数,就是利用函数指针调⽤的函数,通俗来讲,只要是一个函数参数里面有函数指针,都可以被称为回调函数

例如:完成一个简易的计算器,要求输入1代表计算加法,2代表计算减法,3代表计算乘法,4代表计算除法,0代表退出计算器,选择1 2 3 4其中一个后输入要计算的两个数字,返回计算结果

不使用回调函数的代码如下:

#include <stdio.h> int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { return a/b; } int main() { int x, y; int input = 0; int ret = 0; do { printf("*\n"); printf("* 0:退出 1:add 2:sub *\n"); printf("* 3:mul 4.div *\n"); printf("*\n"); printf("请选择:"); scanf("%d", &input); switch (input) { case 1: printf("输入操作数:"); scanf("%d %d", &x, &y); ret = add(x, y); printf("ret = %d\n", ret); break; case 2: printf("输入操作数:"); scanf("%d %d", &x, &y); ret = sub(x, y); printf("ret = %d\n", ret); break; case 3: printf("输入操作数:"); scanf("%d %d", &x, &y); ret = mul(x, y); printf("ret = %d\n", ret); break; case 4: printf("输入操作数:"); scanf("%d %d", &x, &y); ret = div(x, y); printf("ret = %d\n", ret); break; case 0: printf("退出程序\n"); break; default: printf("选择错误\n"); break; } } while (input); return 0; }

C语言指针详解(函数指针)

可以看到有多个重复的步骤,增加了无意义的工作量,这是我们可以注意到这四个函数(add,sub,mul,div)的函数参数都是两个int类型的变量,返回值也都是int,那么我们就可以使用回调函数来简化代码

简化代码如下:

#include <stdio.h> void menu() { printf("*\n"); printf(" 1:add 2:sub \n"); printf(" 3:mul 4:div \n"); printf(" 0:exit \n"); printf("*\n"); } int Add(int x, int y) { return x + y; } int Sub(int x, int y) { return x - y; } int Mul(int x, int y) { return x * y; } int Div(int x, int y) { return x / y; } //回调函数 void Callback(int (*pfun)(int,int)) { int x = 0; int y = 0; int ret = 0; printf("请输入两个数字:"); scanf("%d %d",&x,&y); ret = pfun(x,y); printf("结果为:%d\n",ret); } int main() { int input = 0; do { menu(); printf("请输入你的选择:----->"); scanf("%d",&input); switch(input) { case 1: Callback(Add); break; case 2: Callback(Sub); break; case 3: Callback(Mul); break; case 4: Callback(Div); break; case 0: printf("退出计算器!"); break; default: break; } }while(input); return 0; } 

C语言指针详解(函数指针)

运用回调函数之后,整个代码会简洁许多,并且方便阅读

现在我们来仔细看看这个回调函数是怎么实现的:

void Callback(int (*pfun)(int,int)) { int x = 0; int y = 0; int ret = 0; printf("请输入两个数字:"); scanf("%d %d",&x,&y); ret = pfun(x,y); printf("结果为:%d\n",ret); }

可以看到该回调函数的函数名为Callback,函数参数是一个名为pfun的函数指针,返回值为void,假设用户输入1时,便将add的地址传入Callback中,从而不需要在主函数中提示用户输入和调用add函数(主函数调用的全是Callback函数)

Callback(add)  //该语句将add地址传入

综上所述:

回调函数类似于一个中间商,再调用其他有用的函数

C语言指针详解(函数指针)

2.2qsort 

我们之前说过冒泡排序,但是冒泡排序只能够对整数进行操作

qsort()函数可以对任意类型进行排序 

先看 qsort() 函数的官方定义(若要使用qsort函数,需要头文件<stdlib.h>

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))

 其中

  • base 是一个数组指针,指向要排序的数组的第一个元素
  • nitems 是数组的元素个数(可以用 sizeof(数组名)/sizeof(数组首元素) 求得)
  • size 是数组中每个元素的大小,以字节为单位(可以用 sizeof(数组首元素)  求得)
  • compar 是一个函数指针,返回类型是 int ,函数参数是 const void * ,const void *(相当于函数的参数和返回类型都是确定的,不可以修改)

我们来举一个实例:

#include <stdlib.h> #include <stdio.h> Print(int * pArr,int sz) { int i = 0; for(i = 0;i<sz;i++) { printf("%d ",pArr[i]); } printf("\n"); } int compare_int(const void * p1,const void * p2) { //void * 不能直接解地址,因为我们知道是int类型,可以进行强制类型转换 return *(int *)p1 - *(int *)p2; } void test() { int arr[10] = {123,56,74,856,325,,856,24,98,76}; int sz = sizeof(arr)/sizeof(arr[0]); Print(arr,sz); qsort(arr,sz,sizeof(arr[0]),compare_int); Print(arr,sz); } int main() { test(); return 0; } 

qsort(arr,sz,sizeof(arr[0]),compare_int)

qsort函数中的compare_int就是我们自己写的一个函数名字(函数名保存的是函数地址,函数指针保存的也是函数地址,这里可以将函数名等量看作函数指针,直接写函数名即可)

以上仅是我个人对C语言指针的浅薄理解,如有错误,还请指正! 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/119452.html

(0)
上一篇 2025-11-05 13:20
下一篇 2025-11-05 13:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信