简单声明一个函数指针并不意味着它可马上就可以使用。和其他指针一样,对函数指针执行间接访问之前必须把它初始化指向某个函数。如下代码:
# include <stdio.h>
int fun(int x)
{
return x;
}
int main()
{
int (*pf)(int) = &fun;//声明并初始化函数指针,该指针指向fun()函数
//初始化表达式中的&操作符是可选的,因为函数名被使用时总是由编译器把它转换为函数指针
//int (*pf)(int) = fun
int t = fun(10);
t = (*pf)(10);
t = pf(10);
return 0;
}
代码中使用了三种函数调用方式:
1、使用函数名调用。这样的调用方式执行过程是:首先函数名fun被转化成一个函数指针,该指针指定函数在内存中的位置。然后,函数调用操作符调用该函数,执行开始于这个地址的代码。
2、第二种对pf执行间接访问操作把函数指针转换为一个函数名(*pf),这个转换并不是真正需要,因为在执行调用操作时又会将其转换成一个指针,语句的执行效果和第一种相同
3、直接用函数指针调用。
一、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
如果要实现一个通用的冒泡排序,即对任意数据类型进行排序:冒泡排序的代码结构是固定的,但是不同的自定义类型,会有不同的比较方式和不同的交换方法。采用一般方法一个冒泡排序只可以对一种自定义结构类型数据进行排序,但是采用回调函数,如果给定自定义数据类型的比较方法和交换方式即可做到用一个冒泡排序对所有自定义结构类型数据进行排序
# include <stdio.h>
# include <string.h>
typedef struct
{
int key;
char name[10];
bool sex;
}Node;
typedef bool(*Compare)(void *,void *);//声明函数指针类型,比较函数
typedef void(*Swap)(void *,void *);//声明函数指针类型,交换函数
//通用的冒泡排序
void Bupple(Node *arr,int len,Compare pc,Swap sw)
{
for (int i = 0; i < len - 1; ++i)
{
for (int j = 0; j < len - 1 - i; ++j)
{
if (pc(&arr[j], &arr[j + 1]))
{
sw(&arr[j], &arr[j + 1]);
}
}
}
}
//自定义比较函数
bool compare(void *a,void *b)
{
Node *p = (Node *)a;
Node *q = (Node *)b;
if(p->key > q->key)
{
return true;
}
else
{
return false;
}
}
//自定义交换函数
void swap(void *a,void *b)
{
Node *p = (Node *)a;
Node *q = (Node *)b;
Node tmp;
tmp.key = p->key;
strcpy(tmp.name, p->name);
tmp.sex = p->sex;
p->key = q->key;
strcpy(p->name, q->name);
p->sex = q->sex;
q->key = tmp.key;
strcpy(q->name,tmp.name);
q->sex = tmp.sex;
}
//打印函数
void Show(Node *arr, int len)
{
for (int i = 0; i < len; ++i)
{
printf("%d %s %d\n", arr[i].key, arr[i].name, arr[i].sex);
}
}
int main()
{
Node arr[] = {23,"wang", true, 12, "zhang", false, 18,"li", true};
Bupple(arr, 3, compare,swap);
Show(arr, 3);
return 0;
}