上次我们说到了函数指针,对于函数指针大家还不太清楚的参考,指针进阶(一)http://t.csdn.cn/z5cjM
函数指针数组
数组是存放相同类型的空间,前面我们已经学习了指针数组
int* arr[10] 每个元素是int*
那么我们把函数的地址存放到一个数组中,这个数组我们就称为函数指针数组,函数指针数组怎么书写呢?
一个·函数指针 int(*pa)(int ,int)=函数地址
多个函数指针就是函数指针数组了
上面是通过伪代码的形式呈现,那么在实际应用有·什么用呢,我们举一个例子
设计一个计算器,程序不难
#include <stdio.h>
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 main()
{
//int (*pa)(int, int) = 函数名;
//int (*ppa[5])(int, int) = { 函数名,函数名,函数名,函数名,函数名 };
int x = 0;
int y = 0;
int ret = 0;
int input = 1;
int(*pa[5])(int ,int ) = { NULL,add,sub,mul,div };
while (input)
{
printf("***************************************\n");
printf("**** 1.add 2.sub *********\n");
printf("**** 3.mul 4.div *********\n");
printf("**** 0.结束 *********\n");
printf("***************************************\n");
printf("请输入->\n");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
printf("请输入操作数->\n");
scanf("%d %d", &x, &y);
ret = (*pa[input])(x, y);
}
else
{
printf("输入错误,重新输入\n");
}
printf("%d\n", ret);
}
return 0;
}
指向函数指针数组的指针
指向函数指针数组的指针也就是一个指针,这个指针 指向 函数指针数组
就如上面的函数指针数组:int(*pa[5])(int ,int ) = { NULL,add,sub,mul,div };
我们怎么写一个指针指向这个函数指针数组
回调函数
回调函数就是一个通过函数指针的调用的函数
如果你把函数的指针(地址)作为参数传递给另外的函数,当这个指针被用来调用其所指向的函数时,我们就说这个是回调函数
库函数中有一个函数qsort
qsort函数的作用是可以进行数据的排序
首先我们要了解qsort函数,通过cplusplus网
看不懂不要紧,下面也有例子
说那么多还是看实例吧
//从小到大排
#include <stdio.h>
#include <stdlib.h>
int sort_int(const void*e1, const void*e2)
{
return *(int*)e1 - *(int*)e2;
}
int main()
{
int arr[] = { 5,6,7,8,9,0,1,2,3,4 };
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), sort_int);
int ret = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < ret; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
有人说我要从大到小怎么办
#include <stdio.h>
#include <stdlib.h>
int sort_int(const void*e1, const void*e2)
{
return *(int*)e2 - *(int*)e1;
}
int main()
{
int arr[] = { 5,6,7,8,9,0,1,2,3,4 };
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), sort_int);
int ret = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < ret; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
将return 里面的两个相减数交换位置就好了
整型的排序我们会了,字符型,结构体的排序呢
字符型
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int sort_char(const void* e1, const void* e2)
{
return *(char*)e1 - *(char*)e2;
}
int main()
{
char arr[] = "acbed";
qsort(arr, strlen(arr), sizeof(arr[0]), sort_char);
int ret = sizeof(arr) / sizeof(arr[0]);
printf("%s", arr);
return 0;
}
//结构体
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct str
{
char name[20];
int age;
};
int sort_struct(const void* e1, const void* e2)
{
return ((struct str*)e1)->age - ((struct str*)e2)->age;
}
int main()
{
struct str s[] = { {"xiao ming",23},{"li hua",20},{"wang wu",21} };
qsort(s, sizeof(s)/sizeof(s[0]), sizeof(s[0]), sort_struct);
return 0;
}
那么qsort函数是怎么实现的,我们在之前学过冒泡排序,就是排整型数据的,qsort内部是使用快速排序的,今天我们利用冒泡排序的思想模拟qsort函数
先回忆一下冒泡排序
#include <stdio.h>
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 - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[] = { 1,2,3,4,0,8,9,7,6,5 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
但是冒泡排序只能排整型,不能排字符型,也不能排结构体
我们设计一个兼容可以排序整型,又可以排字符型和结构体的呢
模拟qsort的思想,利用冒泡的形式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct str
{
char name[20];
int age;
};
int sort_jud_int(void* e1, void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int sort_jud_char(void* e1, void* e2)
{
if (*(char*)e1 > *(char*)e2)
return 1;
else
return -1;
}
int sort_jud_struct_age(void* e1, void* e2)
{
return ((struct str*)e1)->age - ((struct str*)e2)->age;
}
int sort_jud_struct_name(void* e1, void* e2)
{
return strcmp(((struct str*)e1) ->name,((struct str*)e2) ->name);
}
void swap(char* base1, char* base2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *base1;
*base1 = *base2;
*base2 = tmp;
base1++;
base2++;
}
}
void my_qsort(void* base, int sz, int width,int (*pa)(void*,void*))
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for (j = 0; j < sz - i - 1; j++)
{
if (pa((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
void test1()
{
int arr[] = { 5,6,7,8,9,0,1,2,3,4 };
int ret = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, ret, sizeof(arr[0]), sort_jud_int);
int i = 0;
for (i = 0; i < ret; i++)
{
printf("%d ", arr[i]);
}
}
void test2()
{
char arr[] = "acdeba";
my_qsort(arr, strlen(arr), sizeof(arr[0]), sort_jud_char);
puts(arr);
}
void test3()
{
struct str s[3] = { {"zhangsan",23},{"lisi",20},{"wangwu",19} };
int ret = sizeof(s) / sizeof(s[0]);
//my_qsort(s, ret, sizeof(s[0]), sort_jud_struct_age);
my_qsort(s, ret, sizeof(s[0]), sort_jud_struct_name);
}
int main()
{
//test1();//整型
//test2();//字符串
test3();//结构体
return 0;
}
整体代码是上述的,是怎么实现的,我们一步一步剖析
上面是对一个大局部进行剖析,字符型和结构体的大同小异
我们理一理我们设计的my_qsort函数
那么谁是回调函数呢
有概念说,把函数的指针作为参数传递给另外的函数,当这个指针用来调用其所指向的函数的时候,我们就是说这个是回调函数
这样看来我们可以称sort_jud_int函数为回调函数了
回调函数的使用多种多样,结合指针,我们可以玩出多种多样的花样