目录
1.函数指针数组
函数指针数组是存放函数指针的数组,其本质上还是数组,其中的元素为函数指针。
int test(int a,int b)
{
return a+b;
}
int(*p)(int,int)=test;
我们可知p为函数test的指针,那函数指针数组应该怎么写呢?
int(*p1[1])(int,int)={p};
这需要在函数指针的基础上进行书写,只要在指针名的后面加上数组的大小即可。
分析:p1先与[]结合,说明p是数组,将数组取出,剩下:int (*)(int,int),这表示数组中的元素都为函数指针,函数返回值为int类型。
2.函数指针数组的简单应用
我们接下来利用函数指针数组实现一个整形简单计算器。
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;
}
我们首先想到的就是用switch语句进行不同分支的判断,然后再使用相应功能的函数进行计算。
int main()
{
int num = 0;
do
{
menu();
scanf_s("%d", &num);
switch (num)
{
case 0:
printf("exit!\n");
break;
case 1:
printf("请输入操作数:");
scanf_s("%d %d", &a, &b);
int ret = add(a, b);
printf("%d\n", ret);
break;
case 2:
printf("请输入操作数:");
scanf_s("%d %d", &a, &b);
int ret = sub(a, b);
printf("%d\n", ret);
break;
case 3:
printf("请输入操作数:");
scanf_s("%d %d", &a, &b);
int ret = mul(a, b);
printf("%d\n", ret);
break;
case 4:
printf("请输入操作数:");
scanf_s("%d %d", &a, &b);
int ret = div(a, b);
printf("%d\n", ret);
break;
default:
printf("请重新输入:");
}
} while (num);
return 0;
}
正如这段代码所示,虽然可以成功实现功能,但代码冗余度太大,我们仔细观察,会发现每次进入case后,只有调用的函数不同,其余都相同,因此我们可以利用函数指针数组来简化代码。
int main()
{
int num = 0;
int a = 0;
int b = 0;
int ret = 0;
do
{
menu();
printf("请输入:");
scanf_s("%d", &num);
int(*ptarr[5])(int, int) = { 0,add,sub,mul,div };
if (num > 0 && num < 5)
{
printf("请输入操作数:");
scanf_s("%d %d", &a, &b);
ret = ptarr[num](a, b);
printf("%d\n", ret);
}
else if (num == 0)
printf("exit!\n");
else
printf("请重新输入:\n");
} while (num);
return 0;
}
我们使用一个函数指针数组存放这四种运算,通过输入下标来调用相对应的函数来实现对应的功能。这样做就减少了冗余度,提高了代码的通用性。
除这两种方法之外,我们还可以利用回调函数来实现。
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
//回调函数;通过调用函数指针来实现被调用函数的功能
void crl(int(*p)(int, int))//形参为函数指针,p为函数指针,指向被调用函数
{
int a = 0;
int b = 0;
printf("请输入操作数:");
scanf_s("%d %d", &a, &b);
int ret = p(a, b);//利用函数指针
printf("%d\n", ret);
}
int main()
{
int num = 0;
do
{
menu();
scanf_s("%d", &num);
switch (num)
{
case 0:
printf("exit!\n");
break;
case 1:
crl(add);
break;
case 2:
crl(sub);
break;
case 3:
crl(mul);
break;
case 4:
crl(div);
break;
default:
printf("请重新输入:");
}
} while (num);
return 0;
}
我们把重复的部分写成一个函数crl,形参为函数指针,所传入的实参为加减乘除的四个函数的地址。当我们想使用不同功能时,直接调用crl,只需要改变传入的实参部分即可。
2.qsort函数
void qsort (void* base, //指向了需要排序的数组的第一个元素
size_t num, //排序的元素个数
size_t size,//一个元素的大小,单位是字节
int (*cmp)(const void*, const void*)//函数指针类型 - 这个函数指针指向的函数,能够比较base指向数组中的两个元素
);
我们可以从cplusplus中得到qsort函数的定义,他的形参部分由以下四部分组成:指向需要排序数组首元素的无类型指针,需要排序的元素个数,一个元素的大小,指向一个可以实现比较功能的函数的指针。
以下为示例:
//qsort整形排序
int cmplete(const void* p1, const void* p2)
{
return(*(int*)p1 - *(int*)p2);
}
void print(int arr[],int sz)
for (int i = 0; i < sz; i++)
printf("%d ", arr[i]);
void test1()
{
int arr[] = { 0,7,9,8,6,5,4,3,5,2,4,6,7 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmplete);
print(arr, sz);
}
3.qsort的模拟实现
我们接下来用冒泡排序的思想来模拟实现qsort函数。
冒泡排序法:
void bubble_sort(int arr[], int sz)
{
int i = 0;
//趟数
for (i = 0; i < sz - 1; i++)
{
//一趟比较
//两两相邻元素比较
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
我们从中可以看到冒泡排序是有局限性的,它只能够排序整形,其他类型的就不能适用了。
用冒泡排序的思想模拟qsort有以下几点难处:
1.不确定数组类型
2.如何比较相邻两个元素的大小
3.如何交换相邻元素
以下是解决思路:
问题一:不确定数组类型
方法:我们将形参中的首地址元素改为void*类型,之后在使用时强转回所需类型(对应qsort函数形参中第一项)
问题二:如何比较相邻两个元素的大小
因为每种类型的比较方法大不相同,所以需要我们自己设计比较函数,(对应qsort函数形参中第四项)
问题三:如何交换相邻元素
因为每种类型的大小各不相同,因此,我们需要知道数组中的元素大小,然后一个字节一个字节的交换,最终实现交换相邻元素。(对应qsort函数形参中第三项)
以下代码为模拟qsort函数整形比较:
//测试整形比较
int cmp(void* p1, void* p2)//比较函数
{
return(*(int*)p1 - *(int*)p2);
}
void swap(char* p1, char* p2,int size)//交换arr[j],arr[j+1],一个字节一个字节交换
{
int i = 0;
char tmp = 0;
for (i = 0; i < size; i++)
{
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
void my_qsort(void* base, int sz, int size, int (*cmp)(void* , void* ))
{
int i = 0;
int j = 0;
for (i = 0; i < sz; i++)
{
for (j = 0; j < sz - 1 - i; j++)
{
//假设升序cmp返回>0,交换
if ((cmp((char*)base + size * j, (char*)base + size * (j + 1))) > 0)//比较大小,需要比较数的地址,用char为基础得到地址
{
swap((char*)base + size * j, (char*)base + size * (j + 1),size);
}
}
}
}
void test()
{
int arr[] = { 0,7,9,8,6,5,4,3,5,2,4,6,7 };
int sz = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, sz, sizeof(arr[0]), cmp);
print(arr,sz);
}
感谢您的观看!
本人拙见,大佬勿怪 ^v^