int (*p) (int, int);//函数指针
int (*p2[4]) (int, int); //函数指针数组
int (*(*p3)[4])(int, int) = &p2; //取出的是函数指针数组的地址
//p3就是一个指向【函数指针的数组】的指针
从上面代码可以看出:
1. 定义:指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素都是函数指针;
2. 如何定义?
转移表——函数指针数组
void test(const char* str)
{
printf ("%s\n", str);
}
int main()
{
//函数指针pfun
void (*pfun)(const char*) = test;
//函数指针的数组pfunArr
void (*pfunArr[5])(const char*);
pfunArr[0] = test;
//指向函数指针数组pfunArr的指针ppfunArr
void (*(*ppfunArr)[5])(const char *) = &pfunArr;
3. 回调函数
回调函数是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
4.回调函数的使用
举例1
#include <stdio.h>
void menu()
{
printf("*********************************\n");
printf("*************请选择:*************\n");
printf("*************1.加法**************\n");
printf("*************2.减法**************\n");
printf("*************3.乘法**************\n");
printf("*************4.除法**************\n");
printf("*************0.退出**************\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;
}
int Calc(int (*pf) (int, int))
{
int x = 0;
int y = 0;
printf("请输入2个操作数:>");
scanf_s("%d %d", &x, &y);
return pf(x, y);
}
int main()
{
menu();
int input = 0;
int ret = 0;
printf("请选择:>");
scanf_s("%d", &input);
switch (input)
{
case 1:
ret = Calc(Add);
printf("ret=%d\n", ret);
break;
case 2:
ret = Calc(Sub);
printf("ret=%d\n", ret);
break;
case 3:
ret = Calc(Mul);
printf("ret=%d\n", ret);
break;
case 4:
ret = Calc(Div);
printf("ret=%d\n", ret);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误,请重新选择\n");
return 0;
}
}
冒泡排序: 涉及到函数指针的调用
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//函数qsort介绍
//void qsort(void* base,size_t num,size_t size,int(*compar)(const void*,const void*));
//base中存放的是待排序数据中第一个对象的地址
//size_t num中cunf排序数据元素的个数
//size_t size中存放一个元素的大小,单位是字节
//int(*compar)(const void*,const void*))比较待排序数据中的2个元素的函数
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
void printf_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz;i++)
{
printf("%d", arr[i]);
}
printf("\n");
}
void test1()
{
//整形数组的排序
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
printf_arr(arr, sz);
}
struct Stu
{
char name[20];
int age;
};
int cmp_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name , ((struct Stu*)e2)->name);
}
void test2()
{
//使用qsort函数排序结构体数据
struct Stu s[] = { {"zhangsan",30},{"lisi",32},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
//按照年龄来排序
//qsort(s, sz, sizeof(s[0]), cmp_age);
//按照名字来排序
qsort(s, sz, sizeof(s[0]), cmp_name);
}
Swap(char* buf1,char* buf2,int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
//实现bubble_sort函数的程序员,他不知道未来排序的数据类型
//程序员也不知道,待比较的两个元素的类型
void bubble_sort(void* base, int sz, int width, int (*cmp)(void*e1, void* e2))
{
int i = 0;
//趟数
for (i = 0; i < sz - 1; i++)
{
//每一趟比较的对数
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
//两个元素比较
if (cmp((char*)base+j*width,(char*)base+(j+1)*width) > 0)
{
//交换
Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
}
}
}
}
void test3()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
//使用bubble_sort的程序员一定知道自己排序的是什么数据
//就应该知道如何比较待排序数组中的元素
bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
}
void test4()
{
//使用qsort函数排序结构体数据
struct Stu s[] = { {"zhangsan",30},{"lisi",32},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
//按照年龄来排序
//bubble_sort(s, sz, sizeof(s[0]), cmp_age);
//按照名字来排序
bubble_sort(s, sz, sizeof(s[0]), cmp_name);
int i = 0;
for(i=0;i<sz;i++ )
{
printf("%s,%d\n", s[i].name, s[i].age);
}
}
int main()
{
//test1();
//test2();
//test3();
test4();
return 0;
}
对定义的bubble_sort()函数的几点说明:
1. 函数的第一个参数传递的是指向一个数组的指针,由于是一个无具体类型的指针void*,这种指针的特点是能够接受任意类型的指针,void*这种指针不能解引用,不能++或者--操作;
2. 函数中第二个参数是数组中元素的个数;
3. 函数中第三个参数是数组中一个元素所占内存的大小,单位是字节;
4. 函数中第四个参数是数组中两个元素进行比较的函数指针*cmp,该指针*cmp指向的比较函数需要用户自己定义;该比较函数的两个参数是指向要进行比较的两个元素的指针,指针的类型也是void*,可以接收任意类型的指针;
(1)在bubble_sort函数中对cmp进行传参的时候,base进行了char*的强制类型转换,原因是为了能够跳过j个width的元素,不断让相邻两个元素进行比较;
(2)Swap函数,不仅要传入要交换的两个元素,还需要传入width,这样才能把这个元素中的每一对字节里存的数据交换到,因为base被强转成了char*的类型,交换一次只能交换一对字节的数据;