对指针的详细认识(三)一一函数指针+函数指针数组+回调函数

函数指针

函数指针的定义

函数指针和我们学习的数组指针十分相似。
我们知道,整型指针是指向整型的指针,数组指针是指向数组的指针,其实,函数指针就是指向函数的指针。
和学习数组指针一样,学习函数指针我们也需要知道三点:
1、()的优先级要高于 * 。
2、一个变量除去变量名,便是它的变量类型。
3、一个指针变量除去变量名和*,便是指针指向内容的类型、

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int(*p)(int, int) = &Add;
	return 0;
}

那么,函数指针p的类型我们是如何创建的呢?
首先p是一个指针,所以必须先与 * 结合,但是()的优先级要高于 * ,所以
我们要把 * 和p用括号括起来,让它们先结合。
指针p指向的内容,即函数Add的类型是int(int,int),所以函数指针p就变成了int(*p)(int,int)。
去掉变量名p后,便是该函数指针的变量类型int( * )(int,int)。
在这里插入图片描述

函数指针的使用

1、函数指针的赋值:
对于数组来说,数组名跟&数组名代表的意义不同,数组名是首元素地址,&数组名是整个数组的地址。
但是对于函数来说,函数名和&函数名他们代表的意义是相同的,它们都代表函数的地址。
所以,当我们对函数指针赋值的时候,可以赋值为函数名,也可以赋值为&函数名。

int(*p)(int, int) = Add;
int(*p)(int, int) = &Add;

2、通过函数指针调用函数:
1.函数指针存放的是函数的地址,我们将函数指针解引用,便能找到该函数,然后就可以通过函数指针调用该函数。

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;
	int(*p)(int, int) = Add;
	int ret = (*p)(a, b);//解引用找到Add
	printf("%d", ret);
	return 0;
}

我们可以理解为*和&是两个相反的操作符,一个 * 操作符可以抵消一个&操作符。
在这里插入图片描述
2、我们知道,函数名跟&函数名都代表函数的地址,我们赋值时可以直接赋值函数名,所以我们通过函数指针调用函数的时候就不需要解引用操作就能找到该函数。

![#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;
	int(*p)(int, int) = Add;
	int ret = p(a, b);//不用解引用
	printf("%d", ret);
	return 0;
}

在这里插入图片描述

函数指针数组

函数指针数组的定义

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组,
比如:

int *arr[10];
//数组的每个元素是int*

那如果要将一系列相同类型的函数指针存放到一个数组中,那么这个数组就是函数指针数组:

int (*parr1[10])();
//数组parr1有10个元素,每个元素的类型是int(*)(int,int)

函数指针数组的创建只需在函数指针创建的基础上加上【】就可以了。

函数指针数组的使用——模拟计算器

#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 = 0;
  int y = 0;
  int input = 1;
  int ret = 0;
  int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //函数指针数组-转移表
  while (input)
  {
     printf( "*************************\n" );
     printf( " 1:add      2:sub \n" );
     printf( " 3:mul      4:div \n" );
     printf( "*************************\n" );
     printf( "请选择:" );
   scanf( "%d", &input);
     if ((input <= 4 && input >= 1))
    {
     printf( "输入操作数:" );
       scanf( "%d %d", &x, &y);
       ret = (*p[input])(x, y);
    }
     else
       printf( "输入有误\n" );
     printf( "ret = %d\n", ret);
  }
   return 0;
}

代码中,函数指针数组存放的是一系列参数和返回类型相同的函数名,即函数指针。将0放在函数指针数组的第一位是为了让用户输入的数字input与对应的函数指针下标相对应。其实还可以选择一系列switch的分支语句也能达到想要的效果,但会使代码出现许多重复内容,当以后需要增加一个函数又需要增加一个case语句,而使用函数指针数组,当你想要增加计算机功能时,只需要在数组中增加一个函数即可。

指向函数指针数组的指针是一 个指针

指针指向一个 数组 ,数组的元素都是 函数指针 ;

int main()
{
	int(*p)(int, int);
	//函数指针
	int(*p1arr[10])(int, int);
	//函数指针数组
	int(*(*p2)[10])(int, int);
	//指向函数指针数组的指针
	return 0;
}

如何定义?

在这里插入图片描述
所以p2就是一个指向函数指针数组的指针,该函数指针数组的每个元素类型都是int(*)(int,int)。

回调函数

回调函数的定义

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个
函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数
的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进
行响应。

void test1()
{
	printf("hello csdn");
}
void test2(void(*p)())
{
	p();//指针p被用来调用其所指向的函数
}
int main()
{
	test2(test1);//将test1函数地址传递给test2
	return 0;
}

在该代码中test1函数不是由该函数的实现方直接调用,而是将其地址传给test2函数,在test2函数中通过指针间接调用了test1函数,那么test1函数就被称为回调函数。

回调函数的使用-qsort函数

void qsort(void* base, size_t num, int(*compare)(const void* e1, const void* e2));

qsort函数第一个参数是待排序内容的起始位置,第二个参数是从起始位置开始,待排序元素的个数,
第三个参数是待排序每个元素的大小,单位是字节,第四个参数是一个函数指针。
qsort函数第四个参数是一个函数指针,该函数指针指向的函数的两个参数类型都是const void*,返回类型是int。当参数e1小于参数e2时返回小于0的数字,e1大于e2时返回大于0的数字,e1等于e2时返回0。

int compare(const void* e1, const void* e2)
{
	return *((int*)e1) - *((int*)e2);
}
int main()
{
	int arr[] = { 2,4,7,6,8,3,1 };
	int sz = sizeof(arr)/sizeof(arr[0]);
	qsort(arr, sz, 4, compare);
	return 0;
}

最终arr数组将被排成升序。
qsort函数默认将待排序的内容排为升序,如果我们要排成降序可以将比较函数的两个形参交换一下位置。

在qsort函数中我们传入一个函数指针,最终qsort函数会在其内部通过函数指针调用该函数,我们这个自定义比较函数就被称为回调函数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值