(一)什么是函数指针
(1)函数指针的定义
- 简单来说,是一种指向函数地址的指针。
- 定义函数指针语法:
返回值类型 (*指针名)(形参类型列表); - 使用函数指针语法:
函数指针变量名 = 函数名; 函数指针变量名 = &函数名;
注意:
- 函数指针具有类型
根据所指的函数参数类型、个数、以及返回值的类型不同,所定义的函数指针类型不同 - 定义也可使用typedef 进行类型重命名
typedef int (*pfun)(int, int) TYPE_FUN; TYPE_FUN 函数指针变量 = 函数名;
(2)函数指针的使用
下面简单使用函数指针,直接调用sum函数
#include <stdio.h>
int sum(int a, int b)
{
return a + b;
}
int main()
{
int a =10;
int b = 20;
int (*pfun)(int, int) = ∑
printf("a + b = %d \n", (*pfun)(a, b));
return 0;
}
结果:
(二)回调函数
(1) 回调函数定义
函数形参列表中含有函数指针变量的函数叫做回调函数。
(2) 回调函数的作用
通过回调函数去调用函数指针所指向的函数。
(3)回调函数的使用
-
众所周知,linux下的多线程的创建函数thread_create(),就是一个回调函数,下面是这个函数的声明,我们简单来看看。 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); 我们可以看到函数的第三个形参void *(*start_routine) (void *) 这就是一个函数指针,该函数指针形参类型是一个void*类型,函数的返回值也是void*类型 这个函数就暂时看到这… -
下面我们自己编写一个回调函数,并使用它
- 写个冒泡排序,从小到大,从大到小两种输出结果,但只能手动调用同一个排序函数
#include <stdio.h>
int SmallToBig(int a, int b)
{
return a > b ? 1 : 0;
}
int BigToSmall(int a, int b)
{
return a < b ? 1 : 0;
}
void Swap(int* p, int* q)
{
int tmp = 0;
tmp = *p;
*p = *q;
*q = tmp;
}
void BubbleSort(int* arr, int len, int (*compare)(int, int))
{
if(arr == NULL || compare == NULL || len <= 0)
return;
int i = 0;
int j = 0;
for(i = 0; i < len - 1; i++)
{
for(j = 0; j < len - i - 1; j++)
{
if((*compare)(arr[j], arr[j + 1]) == 1)
{
Swap(&arr[j], &arr[j + 1]);
}
}
}
}
void ShowArr(int* arr, int len)
{
if(arr == NULL || len <= 0)
return;
int i;
for(i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {12, 22, 10, 8, 45, 26, 30, 15, 16, 12};
int len = sizeof(arr) / sizeof(arr[0]);
printf("small to big: ");
BubbleSort(arr, len, SmallToBig);
ShowArr(arr, len);
printf("big to small: ");
BubbleSort(arr, len, BigToSmall);
ShowArr(arr, len);
return 0;
}
结果:
(三)什么是函数指针数组
(1)函数指针数组的定义
- 定义语法:
返回值类型 (*变量名[元素个数])(形参类型..) = {同类型函数名}; - (推荐写法)
typedef 返回值类型 (*函数指针变量名)(参数类型..); 函数指针变量名 数组名[元素个数]; - 调用函数指针数组中的函数
变量名[下标](实参列表);
(2)函数指针数组的使用
分别写出加减乘除的四个函数,将其存放在函数指针数组中,通过数组中的元素来调用四个函数。 代码:
#include <stdio.h>
#include <limits.h>
int sum(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
if (b == 0) return INT_MAX;
return a / b;
}
int main()
{
int (*pfun[4])(int, int) = { &sum, &sub, &mul, &div };
int a = 100;
int b = 50;
printf("a + b = %d\n", pfun[0](a, b));
printf("a - b = %d\n", pfun[1](a, b));
printf("a * b = %d\n", pfun[2](a, b));
printf("a / b = %d\n", pfun[3](a, b));
return 0;
}
分析:我们来看看函数指针数组中的元素的类型 结果:
(四)函数指针实现泛型编程
(1)实现一个输出函数,输出不同类型数组中所有元素
#include <stdio.h>
void Show_Int(const void* vp)
{
if(vp == NULL) return;
const int* p = (const int*)vp;
printf("%d ", *p);
}
void Show_Char(const void* vp)
{
if(vp == NULL) return;
const char* p = (const char*)vp;
printf("%c ", *p);
}
void Show_Double(const void* vp)
{
if(vp == NULL) return;
const double* p = (const double*)vp;
printf("%lf ", *p);
}
void ShowArray(const void* arrname, void (*pfun)(const void*), int len, int elemsize)
{
if(arrname == NULL || pfun == NULL || len <= 0)
return;
if(elemsize < 1 || elemsize > 8)
return;
int i;
const char* tmp = (const char*)arrname;
for(i = 0; i < len; i++)
{
(*pfun)(tmp);
tmp += elemsize;
}
printf("\n");
}
void Test()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 9, 10};
int arr_len = sizeof(arr) / sizeof(arr[0]);
ShowArray(arr, Show_Int, arr_len, sizeof(int));
char crr[] = {'h', 'e' , 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '\0'};
int crr_len = sizeof(crr) / sizeof(crr[0]);
ShowArray(crr, Show_Char, crr_len, sizeof(char));
double drr[] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7};
int drr_len = sizeof(drr) / sizeof(drr[0]);
ShowArray(drr, Show_Double, drr_len, sizeof(double));
}
int main()
{
Test();
return 0;
}
结果: (2)使用同一个排序函数,同一个打印函数,将int char类型的数组元素经过排序,打印。
#include <stdio.h>
void Swap_int(void* p, void* q)
{
int tmp = (*(int*)p);
(*(int*)p) = (*(int*)q);
(*(int*)q) = tmp;
}
void Swap_char(void* p, void* q)
{
char tmp = (*(char*)p);
(*(char*)p) = (*(char*)q);
(*(char*)q) = tmp;
}
void Swap_double(void* p, void* q)
{
double tmp = (*(double*)p);
(*(double*)p) = (*(double*)q);
(*(double*)q) = tmp;
}
int Compare_int(const void* a, const void* b)
{
return (*(int*)a) > (*(int*)b) ? 1 : 0;
}
int Compare_char(const void* a, const void* b)
{
return (*(char*)a) > (*(char*)b) ? 1 : 0;
}
int Compare_double(const void* a, const void* b)
{
return (*(double*)a) > (*(double*)a) ? 1 : 0;
}
void BubbleSort(void* arrname, int (*compare)(const void*, const void*), int (*pswap)(const void*, const void*), int len, int elemsize)
{
if (arrname == NULL || compare == NULL || pswap == NULL || len <= 0 || elemsize < 1 || elemsize > 8)
return;
int i;
int j;
for (i = 0; i < len - 1; i++)
{
char* start = (char*)arrname;
for (j = 0; j < len - i - 1; j++)
{
if (compare(start, start + elemsize))
{
pswap(start, start + elemsize);
}
start += elemsize;
}
}
}
void Show_Int(const void* vp)
{
if (vp == NULL) return;
const int* p = (const int*)vp;
printf("%d ", *p);
}
void Show_Char(const void* vp)
{
if (vp == NULL) return;
const char* p = (const char*)vp;
printf("%c ", *p);
}
void Show_Double(const void* vp)
{
if (vp == NULL) return;
const double* p = (const double*)vp;
printf("%lf ", *p);
}
void ShowArray(const void* arrname, void (*pfun)(const void*), int len, int elemsize)
{
if (arrname == NULL || pfun == NULL || len <= 0)
return;
if (elemsize < 1 || elemsize > 8)
return;
int i;
const char* tmp = (const char*)arrname;
for (i = 0; i < len; i++)
{
(*pfun)(tmp);
tmp += elemsize;
}
printf("\n");
}
void Test()
{
int arr[] = { 2, 1, 3, 0, 8, 5, 7, 6, 10 };
int arr_len = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, Compare_int, Swap_int, arr_len, sizeof(int));
ShowArray(arr, Show_Int, arr_len, sizeof(int));
char crr[] = { 'h', 'e' , 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd' };
int crr_len = sizeof(crr) / sizeof(crr[0]);
BubbleSort(crr, Compare_char, Swap_char, crr_len, sizeof(char));
ShowArray(crr, Show_Char, crr_len, sizeof(char));
}
int main()
{
Test();
return 0;
}
结果: 暂不支持double、float类型
|