还是那句,男孩子在外面要保护好自己~
一、函数指针数组
函数指针也是指针,既然指针数组里是存放指针的,那么也必然可以存放函数的指针
(一)格式
我们知道函数指针,如 int (*p) (int, int),类型为 int (*) (int, int)
还有指针数组,如 int * arr[10] , 类型为 int* [10]
那么 函数指针的格式是什么呢?
int (* arr[10]) (int, int)
arr 先和 [10] 结合,表示arr是一个数组,数组有十个元素,每个元素的类型是int (*) (int, int) 类型为函数的地址即函数指针
所以每个元素都是一个函数指针
二、指向函数指针数组的指针
首先,它是一个指针,再者它是数组的指针,而且数组的每个元素是函数指针,那我们就一步一步来(以下为个例)
指针 (*p)
数组的指针:(*p) [10]
每个元素是一个函数指针:int (* (*p) [10] ) (int, int)
三、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
意思是先自定义好了一个函数A,然后把函数名(函数地址)存到指针里,等下在另外一个函数中还要用到函数A,就使用其函数指针来调用函数A,函数A就是一个回调函数。
意思是等下还会用到的那个函数,这个函数就叫回调函数,就有一个要求:用函数指针来调用它
回调,等下还会调用的意思
讲到回调函数就要提到快排 qsort
首先 qsort 函数是一个帮助排序的函数(如把数组排成升序或者说降序)
我们要知道,不仅仅是整型数组可以排序,其他类型如 char类型浮点型数组 也可以排序,还有结构体有时也需要进行排序
一般来说,简单的函数只能排一种类型的数组或只能排结构体(自定义函数形参固定死了)
但是快排 qsort 不同,任意类型的数组或者说结构体它都能排
我这里就有一个问题了,为什么 qsort 函数的形参 能接收 不同类型的数组并将其进行排序(一般来说只能排序一种类型啊)
研究 qsort 函数的参数:
void qsort( viod* base, size_t num, size_t width, int (* cmp) (const void* elem1, const void* elem2) )
首先是 base:base 是目标数组的数组名(数组首元素地址),你要排序的数组名(数组首元素地址)
num :num 表示元素个数
width:width 表示一个元素的大小(所占空间大小,字节为单位)
cmp:从 int (* cmp) (const void* elem1, const void* elem2) 看,首先cmp是一个指针,后面有 () 表示是函数的指针,函数的参数有 elem1、elem2 ,类型为 const void*,是数组的两个元素的地址 ;而该函数返类型为 int。了解到cmp是一个函数指针,函数的地址,等下要调用的(如果记得,会立马反应 cmp 是一个回调函数)
作用:比较数组中的两个元素大小,相减所得的数(可能大于0,小于0,等于0)返回给 qsort ,让qsort给两元素排序
排序基本步骤:
当输入部分完毕后,就要把它进行排序了,接下来那就交给 qsort 函数,但是使用 qsort 函数只要我们做一点:写一个 cmp函数(简单)。
我们只需要写一个简单的 cmp函数,而且大部分是固定格式,底层复杂的排序 qsort 已经给你写好了,就很方便
所以我们只要掌握 cmp函数 怎么写:
刚刚从 qsort 传参里知道了 cmp 函数的参数类型:const void* 和返回类型 int
首先 elem1 的类型:const void* ,说明 elem 是一个 指针,是一串地址。这就是接收两个要进行比较的元素的地址
cmp 的内容:
直接返回量元素相减的值,通过返回的值 大于0 小于0 或等于0 就到qsort内部进行元素相关的排序操作
格式:return 元素 - 元素;
现在只知道 elem 元素的地址,要写成:元素 - 元素;
因为 elem 已经是元素的地址了,但是这里一定要注意,elem 的类型为 const void* 是空类型的(才能做到接收容易类型),而 void*类型 的地址不能进行 解引用 或 加一 等操作,所以也必须先强制类型转换,
转换什么类型要看你排序什么类型的数组,这很重要(cmp意义体现)
如排序 int 类型数组,那就 *(int*)elem1 ,这样就把 elem1 地址类型转换了,再通过解引用可找到该元素
现可达成 元素-元素 格式: return *(int*)elem1 - *(int*)elem2;
而排序我们知道,可以排成升序和降序,在cmp函数里是:
升序: return *(int*)elem1 - *(int*)elem2;
降序: return *(int*)elem2 - *(int*)elem1;
记住也可
总的来说,从地址转换到元素:
1、转换elem类型(再解引用)
2、根据升序降序看是 return (e1 - e2) ,还是 (e2 - e1)
函数指针数组和qsort的结合:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
struct People
{
char name[20];
unsigned int age;
};
int cmp_ch(const void* e1, const void* e2)
{
return *(char*)e1 - *(char*)e2;
}
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int cmp_float(const void* e1, const void* e2)
{
double fret = (*(double*)e1 - *(double*)e2);
return (int)(fret * 100000);
}
int cmp_people_age(const void* e1, const void* e2)
{
return ((struct People*)e2)->age - ((struct People*)e1)->age;
}
int cmp_people_name(const void* e1, const void* e2)
{
//return strcmp(((struct People*)e1)->name, ((struct People*)e2)->name);
return (int)(strlen(((struct People*)e1)->name) - strlen(((struct People*)e2)->name));
}
//排序字符
void test1()
{
char arr[100] = { 0 };
printf("请输入一串字符进行排序:");
scanf("%s", arr);
qsort(arr, strlen(arr), sizeof(arr[0]), cmp_ch);
printf("\n%s\n", arr);
}
//排序整型数组
void test2()
{
int arr[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
printf("\n");
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
//排序浮点型数组
void test3()
{
double arr[10] = { 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_float);
printf("\n");
for (int i = 0; i < sz; i++)
{
printf("%.4lf ", arr[i]);
}
}
//排序结构体变量
void test4()
{
struct People s[5] = { {"yangxinrong", 18}, {"lihuangzhu", 19}, {"xukun", 17}, {"yangjun", 15}, {"laojiang", 17} };
int sz = sizeof(s) / sizeof(s[0]);
char input[10] = { 0 };
printf("请输入 “年龄” 或 “名字长度” 来给其排序:");
scanf("%s", input);
if (0 == strcmp(input, "年龄"))
{
qsort(s, sz, sizeof(s[0]), cmp_people_age);
for (int i = 0; i < sz; i++)
{
printf("\n年龄排名%d :%u\n", i + 1, (s + i)->age);
}
}
else if (0 == strcmp(input, "名字长度"))
{
qsort(s, sz, sizeof(s[0]), cmp_people_name);
for (int i = 0; i < sz; i++)
{
printf("\n名字长度排名 %d:%s\n", (i + 1), (s + i)->name);
}
}
else
{
printf("非法输入\n");
}
}
void menu()
{
printf(" 排序字符串 \n");
printf(" 排序整形数组 \n");
printf(" 排序浮点型数组 \n");
printf(" 排序人名或年龄 \n\n");
printf("输入 “退出程序” 即可退出该程序\n");
printf("请选择一种类型来进行排序(如输入:“排序字符串”):");
}
int main()
{
/*test1();*/
/*test2();*/
do
{
void (*p[5])() = { NULL, test1, test2, test3, test4 };
menu();
char input[20] = { 0 };
scanf("%s", input);
if (0 == strcmp(input, "排序字符串"))
{
(*(p + 1))();
}
else if (0 == strcmp(input, "排序整型数组"))
{
(*(p + 2))();
}
else if (0 == strcmp(input, "排序浮点型数组"))
{
(*(p + 3))();
}
else if (0 == strcmp(input, "排序人名或年龄"))
{
(*(p + 4))();
}
else if (0 == strcmp(input, "退出程序"))
{
break;
}
else
{
system("cls");
printf("非法输入\n");
Sleep(2000);
}
Sleep(3000);
system("cls");
} while (1);
return 0;
}
相关试题就放到后面再更新咯,大家记得电赞哦,不然晚上会梦见小只因哦(真的,昨天晚上我就梦见了)