目录
1.函数指针数组
数组是一个存放相同类型数据的存储空间,
那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组
那函数指针的数组如何定义呢?
int (*pf[10])(int, int);
pf与[10]结合,说明pf是数组,数组的内容是int(*)( )类型的函数指针。
数组大小可以不写,但一定要赋初值。
用途:转移表
在计算器中我们可以用到转移表 。
首先我们写出实现计算器“加减乘除”功能的函数。
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 x = 0,y = 0;
do {
menu();
printf("请选择:>");
scanf("%d", &input);
int (*pfArr[])(int, int) = { NULL,Add,Sub,Mul,Div };
if (input == 0)
printf("退出计算器\n");
else if (input >= 1 && input <= 4) {
printf("请输入两个整数\n");
scanf("%d %d", &x, &y);
int ret = pfArr[input](x, y);
printf("ret = %d\n", ret);
}
else
printf("选择错误,重新选择!\n");
} while (input);
return 0;
}
通过do—while语句开始执行程序,由input的值觉得程序是否运行。
首先输入input的值,然后创建函数指针数组int (*pfArr[ ])(int, int),
并为其赋值 {NULL,Add,Sub,Mul,Div },数组下表为0处赋值NULL,以便输入input值从1开始。
int (*pfArr[ ])(int, int) = { NULL,Add,Sub,Mul,Div };这就是转移表
将加减乘除函数储存(转移)到pfArr[ ]函数指针数组中。
然后通过input的值选择是否进行计算、进行什么计算
如果进行计算,则输入参与运算的两个整数,通过int ret = pfArr[input](x, y)调用函数指针数组中储存的对应函数,并传输输入的”x“和“y”进行计算。
最后输出计算结果ret的值。
2.指向函数指针数组的指针
void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
//函数指针pfun
void (*pfun)(const char*) = test;
//函数指针的数组pfunArr
void (*pfunArr[5])(const char* str);
pfunArr[0] = test;
//指向函数指针数组pfunArr的指针ppfunArr
void (*(*ppfunArr)[5])(const char*) = &pfunArr;
return 0;
}
3.回调函数
案例:
void calc(int (*pf)(int, int))
{
int x = 0, y = 0;
int ret = 0;
printf("请输入2个操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
int main()
{
int input = 0;
int x = 0, y = 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);
return 0;
}
通过switch—case语句实现输入不同input值进行不同运算,每次都通过calc函数实现计算器功能。
然后创建calc函数,参数定义为一个函数指针pf,pf有两个整型参数,用于接收进行计算的两个整数,将不同功能的加减乘除函数作为参数通过传入calc函数,定义ret = pf(x, y)调用传入pf的函数,然后返回函数输出结果。
当需要进行对应计算时,将所需加减乘除函数作为参数传递给calc函数储存在函数指针pf中,通过自定义变量ret调用pf实现传入的对应加减乘除函数,这就是回调函数。
qsort函数
qsort是一个库函数,包含在<stdlib.h>头文件中,底层使用快速排序的方式,对数据进行排序,可以直接使用,可以用来排序任意类型的数据。
//void* 类型指针不能进行解引用操作符,也不能进行+-整数的操作符
//void* 是用来存放任意类型数据的地址
//void* 无具体类型的指针
void qsort(void* base, //待排序数组的第一个元素
size_t num, //待排序数组的元素个数
size_t size,//待排序数组中一个元素的大小
int (* cmp)(const void* e1,const void* e2))//函数指针指向比较函数
//e1和e2中存放的是需要比较的两个元素的地址
//排序整型数据,两个整型可以直接使用>比较
//排序结构体,两个结构体数据可能不能直接使用<>比较
//也就是不同类型数据,比较大小,方法有差异
排序数组 :
#include <stdio.h>
#include <stdlib.h>
void print_arr(int arr[], int sz)
{
for (int 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 test1()
{
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()
{
test1();
return 0;
}
- 定义函数print_arr用于打印排序结果。
- 创建cmp_int比较函数,传入参数类型可以是任意, 使用
const
关键字修饰函数参数表示这些参数是只读的,无法修改. - 将
e1
和e2
强制转换为指向整数的指针 (int*
)。e1
和e2
通常被声明为const void*
,这是因为qsort
函数要求比较函数的参数是const void*
类型,因此在比较之前需要将它们强制转换回整数指针。 *(int*)e1
和*(int*)e2
:这部分是解引用操作,它们将指针转换为指向的整数值。因为e1
和e2
已经被强制转换为整数指针,所以*(int*)e1
和*(int*)e2
分别表示两个整数。
- 减法操作符用于计算两个整数之间的差值。
- 整个表达式计算两个整数的差值,然后将结果返回。
- 如果结果为正数,则表示第一个整数大于第二个整数。
- 如果结果为负数,则表示第一个整数小于第二个整数。
- 如果结果为零,则表示两个整数相等。
排序结构体:
学会qsort之后,我们还可以排序各种类型,比如结构体类型。
#include <stdio.h>
#include <stdlib.h>
struct Stu
{
char name[20];
int age;
};
//结构体输出函数
void print_arrr(struct Stu arr[], int sz)
{
for (int i = 0; i < sz; i++) {
printf("%s: %d\n", arr[i].name, arr[i].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 arr1[] = { {"zhangsan",20},{"lisi",30},{"王五",12} };
int sz = sizeof(arr1) / sizeof(arr1[0]);
qsort(arr1, sz, sizeof(arr1[0]), cmp_stu_by_age);
print_arrr(arr1, sz);
}
//按照名字比较
#include <string.h>
int cmp_stu_by_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
void test3()
{
struct Stu arr1[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 12} };
int sz = sizeof(arr1) / sizeof(arr1[0]);
qsort(arr1, sz, sizeof(arr1[0]), cmp_stu_by_name);
print_arrr(arr1, sz);
}
int main()
{
test2();
test3();
return 0;
}
注意:结构体成员 name
和 age
不需要解引用操作,因为它们是直接存储在结构体中的数据,而不是指针。
下面让我们进入C语言—进阶指针(三)的学习吧!!!