一起来攻克回调函数(学习笔记)

1:回调函数的简单说明

回调函数概念,和应用场景。其实是比较复杂的,但是我们尝试从易到难。

1:我们先了解回调函数,先看代码

 
  1.    #include<stdio.h>
        int test1(int x,int y)
        {
            printf("x+y=%d\n",(x+y));
            return 0;
        }
        void test2( int (*p)(int ,int ))   //这里使用int(*p)();也是可行的,推荐是用这种,不带参数声明的,
        {
            int y=1;
            int z=2;
            (*p)(y,z);
        }
        int main()
        {
            test2(test1);
            return 0;
        }

至少存在3个函数(回调函数+回调者函数+主函数(不一定要是主函数也可以是任意合法函数)

函数2中必须存在一个形参,这个形参必须是函数指针类型void (*p)(),注意空函数指针也能作为形参。而且空指针称为垃圾桶指针(注意不是垃圾指针),什么类型的指针都能赋值给它

我们在函数1(假设为main主函数)中调用test2,此时该把什么参数传递给test2void (*p)()的形参吗?是不是应该给个函数名(本质是该函数的入口地址),于是我们把tset1作为实参,传递出去。

此时,代码跑到test2函数内部。此时我们使用(*p)(y,z),来调用函数test1。这就实现了,在没有调用test1的情况下,实现了test1的功能。

现在让我们把 情况复杂化,假如test2是封装在头文件,或者库中的函数。这个库或头文件中的函数,必须要调用客户自定义的一个函数test1或者要接收test放回的一个值。这时回调函数的意义和作用就显现出来了。

这时有同学问了,什么我大名鼎鼎,无所不能的库函数还要去调用,用户定义的函数,不可能绝对不可能!!

莫急,我们直接来看,c中的qsort()函数。这是关于对数组,字符串自动进行排序的一个库函数。

2:通过详细的示例解释回调函数

我们先来看看这个函数的原型

viod qsort()表明其函数没有返回值。

第一个参数:void *base 是需要排序的字符或数组的首地址。这里必须声明的一点是,void声明一个指针变量,是C中比较特殊的一种用法。

    printf("我们定义一个viod类型的指针*pvoid:");
    void *pvoid;
    printf("打印此空指针的地址%p\n",&pvoid);
    printf("打印此空指针的大小%d\n",sizeof(pvoid));
    printf("看看此空指针+1后地址移动了几位%d",(pvoid+1)-pvoid);

查看一下输出结果:

可以看到void类型指针,系统是一样的为其开辟了内存空间,大小同其他指针变量一样都是8个字节,可以进行算术运算,和自增自减操作。

空指针还能作为函数形参(也就是被调用函数中的参数),此种情况下,任何指针变量和指针常量都能传入到形参中去。但是在实际使用时,必须强制转换。才能正确使用。

注意,void修饰指针变量是合法操作,但是千万不能用void来修饰普通变量。我们在函数声明或定义时,viod fun_1(void),表明,该函数是没有参数的

看第二个参数:size_t mun,是表明该需要排列数组或字符串的个数。

第三个参数:size_t width ,是表明需要排列数组或字符,每一个元素的Byte数,如int arr1[],这个参数就是4,char arr2[],z这个参数就是1。

最后一个参数:一个函数指针,是学习的重点 int(cdcel_*compare)(const void *element1,const void *element));

这是一个函数指针,作为库函数的形参。那么这个参数就可以被传递各种各样的函数名。

于是接下来,我就自己写了个排序函数,并且利用了回调函数的性质。

/*第一个函数是交换函数*/
void Swap(char*e1,char*e2,int width)
{
	for (int i = 0; i < width; i++)
	{

		char tmp = *e1;
		*e1 = *e2;
		*e2 = tmp;
		e1++;
		e2++;
	}
}

int cmp_my(const void* e1, const void* e2)
{
	return *((int*)e1) - (*(int*)e2);
}


void SelfDefine_sort(void *base,int sz,int width,int (*p)(),void(*p2)())
{
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - (1 +i); j++)
		{
			if (p((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				p2((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}
}

void print_char(char *arr,int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%c ", arr[i]);
}
void print_int(int *arr,int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}

#include<stdio.h>
#include<string.h>
int main()
{
    /*先比较int类型的数组*/
	int arr[] = { 90,889,767,56,51,1114,323,21,100 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_int(arr, sz);
	printf("\n");
	SelfDefine_sort(arr, sz, sizeof(arr[0]), cmp_my,Swap);
	print_int(arr, sz);
	/*再比较char类型的字符数组*/
	char Arr_char[] = "WOAIwangjiahang";
	int sz1 = sizeof(Arr_char) / sizeof(Arr_char[0]);
	print_char(Arr_char, sz1);
	printf("\n");
	SelfDefine_sort(Arr_char, sz1, sizeof(Arr_char[0]), cmp_my,Swap);
	print_char(Arr_char, sz1);

	return 0;
}

有了上面的基础,要写出返回类型为函数指针的函数应该不难了,下面这个例子就是返回类型为函数指针的函数:
void (* func5(int, int, float ))(int, int)
{
    ...
}
在这里, func5 以 (int, int, float) 为参数,其返回类型为 void (*)(int, int) 。 

在开始讲解回调函数前,最后介绍一下函数指针数组。既然函数指针也是指针,那我们就可以用数组来存放函数指针。下面我们看一个函数指针数组的例子:


  
  1. /* 方法1 */

  2. void (*func_array_1[5])(int, int, float);

  3. /* 方法2 */

  4. typedef void (*p_func_array)(int, int, float);

  5. p_func_array func_array_2[5];

上面两种方法都可以用来定义函数指针数组,它们定义了一个元素个数为5,类型是 void (*)(int, int, float) 的函数指针数组。

 

相关推荐

  1. 函数详解

    2024-02-20 03:32:01       63 阅读
  2. ajax函数

    2024-02-20 03:32:01       29 阅读
  3. 函数(Language C)

    2024-02-20 03:32:01       50 阅读
  4. 函数的介绍

    2024-02-20 03:32:01       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-20 03:32:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-20 03:32:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-02-20 03:32:01       82 阅读
  4. Python语言-面向对象

    2024-02-20 03:32:01       91 阅读

热门阅读

  1. Uni-App《》

    2024-02-20 03:32:01       51 阅读
  2. MySql5.7之ERROR 1045 (28000)问题处理

    2024-02-20 03:32:01       54 阅读
  3. 1057:简单计算器

    2024-02-20 03:32:01       42 阅读
  4. 微信多开(无需关闭软件)优化

    2024-02-20 03:32:01       57 阅读
  5. 常见的Web前端开发框架推荐

    2024-02-20 03:32:01       48 阅读
  6. Android使用shape定义带渐变色的背景

    2024-02-20 03:32:01       43 阅读
  7. 数据结构与算法分析——C语言描述(更新中)

    2024-02-20 03:32:01       60 阅读
  8. C++知识点总结(16):结构体排序

    2024-02-20 03:32:01       51 阅读