目录
一.函数指针数组
1.知识先知
2.实际应用
(1)普通写法
(2) 函数指针数组(转移表)写法
二.指向函数指针数组的指针
1.知识先知
(1)指向整型数组指针的数组
2. 要点讲解
三.回调函数
1.知识先知
2.实际应用
四.qsort()函数
1.知识先知
(1)有关qsort()函数参数及作用
(2)void*-类型的指针
2.实际应用
(1)整型数据的比较
(2)结构体类型数据的比较
函数指针--指向函数的指针--存放的是函数的地址
函数指针数组--存放函数指针的数组--数组中存放的是函数指针
#include
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int main()
{
int (*pf1)(int, int) = &Add;
int (*pf2)(int, int) = ⋐
//这里可看出pf1和pf2的类型是一样的,都为 int (*) (int ,int)
//创建存放函数指针的数组 pfArr
int (*pfArr[2])(int, int) = { &Add, &Sub};
return 0;
}
模拟实现计算器的功能
#include
//基础写法
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 menu()//菜单
{
printf("****************************************\n");
printf("*******1.ADD 2.SUB *******\n");
printf("*******3.MUL 4.DIV *******\n");
printf("*******0.EXIT *******\n");
printf("****************************************\n");
}
int main()
{
int input = 0;
int a = 0, b = 0;
int result = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入两个数:\n");
scanf("%d %d", &a, &b);
result = Add(a, b);
printf("%d\n", result);
break;
case 2:
printf("请输入两个数:\n");
scanf("%d %d", &a, &b);
result = Sub(a, b);
printf("%d\n", result);
break;
case 3:
printf("请输入两个数:\n");
scanf("%d %d", &a, &b);
result = Mul(a, b);
printf("%d\n", result);
break;
case 4:
printf("请输入两个数:\n");
scanf("%d %d", &a, &b);
result = Div(a, b);
printf("%d\n", result);
break;
case 0:
printf("程序退出\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
}
缺点:随着功能的增加,case情况越来越多,代码冗余量逐渐增加
优化思路: 通过观察可以发现 加减乘除 四个函数的形式参数以及返回类型是一样的,而数组元素的元素类型也是相同,因此我们可以将每一个函数当成一个数组成员来处理
#include
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 menu()
{
printf("****************************************\n");
printf("*******1.ADD 2.SUB *******\n");
printf("*******3.MUL 4.DIV *******\n");
printf("*******0.EXIT *******\n");
printf("****************************************\n");
}
int main()
{
int input = 0;
int a = 0, b = 0;
int result = 0;
do
{
menu();
printf("请选择运算方式:>\n");
scanf("%d", &input);
//函数指针数组
int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };//添加NULL使下标与对应运算函数对齐
if (input == 0)
{
printf("退出计算器\n");
}
else if (input >= 1 && input <= 4)
{
printf("请输入两个数:\n");
scanf("%d %d", &a, &b);
result = pfArr[input](a, b);
printf("%d\n", result);
}
else
{
printf("选择错误,请重新选择!\n");
}
} while (input);
}
注意:该方法使用的前提为函数的返回类型必须一致
int a=10;
int b=20;
int c=30;
int *arr[]={&a,&b,&c};//整型指针数组
int* (*p)[3]=&arr;//p是一个指针,指向整型指针数组的指针
函数指针数组——数组——存放的是函数的地址
int (*pfArr[5])(int ,int)={NULL,Add,Sub,Mul,Div};//pfArr是函数指针数组
int (*(*p)[5])(int ,int))=&pfArr//p是一个指针,指向函数指针数组的指针
回调函数:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
改善计算器
#include
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 calc(int (*p)(int, int))//用函数指针接受函数的地址
{
int a = 0, b = 0;
int result = 0;
printf("请输入两个数:\n");
scanf("%d %d", &a, &b);
result = p(a, b);
printf("%d\n", result);
}
void menu()
{
printf("****************************************\n");
printf("*******1.ADD 2.SUB *******\n");
printf("*******3.MUL 4.DIV *******\n");
printf("*******0.EXIT *******\n");
printf("****************************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
calc(Add);
break;
case 2:
calc(Sub);
break;
case 3:
calc(Mul);
break;
case 4:
calc(Div);
break;
case 0:
printf("程序退出\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
}
qsort()是一个库函数,底层使用的是快速排序的方式对数据进行排序。这个函数可以直接使用,这个函数可以用来排序任意类型的数据
void qsort(void* base,//待排序数组的第一个元素的地址
size_t num,//待排序数组的元素个数
size_t size,//待排序数组中一个元素的大小
int (*cmp)(const void*p1, const void*p2)//函数指针--cmp指向一个函数,这个函数是用来比较两个元素的
)
cmp函数的要求
p1指向元素>p2指向元素时,返回一个大于0的数字
p1指向元素p1指向元素 == p2指向元素时,返回0
1.该类型的指针不能进行解引用的操作
2.该类型的指针不能进行 + - 整数的操作
作用:void*类型的指针是用来存放任意类型数据的地址
int main()
{
char c = 'a';
char* p = &c;
int* pc = &c;//警告:从”char *“到”int *“的类型不兼容
void* pv = &c;//不会报警告
return 0;
}
将数组 arr[]={9,8,7,6,5,4,3,2,1,0}按照升序的方式重新排列
#include
#include
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}//打印
//构造整型数据的比较函数
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}//构造的相关类型数据的比较函数
void test()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
qsort(arr, sz, sizeof(arr[0]), cmp_int);//快速排序函数
print_arr(arr, sz);
}
int main()
{
test();
return 0;
}
结构体数据比较大小
1.按照年龄比
2.按照名字比较
//测试qsort排序结构体数据
struct Stu
{
char name[20];
int age;
};
//按照年龄比
int cmp_stu_by_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void test2()
{
struct Stu arr[] = { {"zhangsan",20},{"lisi",30},{"wangwu",12}};
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}
int main()
{
test2();
return 0;
}
//测试qsort排序结构体数据
struct Stu
{
char name[20];
int age;
};
//按照姓名比
int cmp_stu_by_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);//比较字符串用strcmp
}
void test2()
{
struct Stu arr[] = { {"zhangsan",20},{"lisi",30},{"wangwu",12}};
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}
int main()
{
test2();
return 0;
}