1.声明与调用

// 声明函数
int f(int);
// 声明并赋值函数指针
int (*pf)(int) = &f;

int ans;
ans = f(25);
ans = (*pf)(25);
ans = pf(25);

通过函数名调用函数时,函数名会被转换为一个函数指针,该指针指定函数在内存中的位置,然后,函数调用操作符调用该函数,执行开始于这个地址的代码。所以通过函数名调用与通过函数地址调用效果相同。

2.应用

a.回调函数

在链表中寻找value,并返回节点指针

Node *search_list(Node *node, int const value)
{
    while (node != NULL) {
        if (node->value == value) {
            break;
        }
        node = node->link;
    }
    return node;
}

更通用的做法:

Node *search_list(Node *node, void const *value, int (*compare)(void const *, void const *))
{
    while (node != NULL) {
        if (compare(&(node->value), value) == 0) {
            break;
        }
        node = node->link;
    }
    return node;
}

// 比较函数
int compare_ints(void const *a, void const *b){
    if (*(int *)a == *(int *)b) {
        return 0;
    } else {
        return 1;
    }
}

// 使用
desired_node = search_list(root, &desired_value, compare_ints);

b.转移表

一种数据驱动方法, 将操作函数存入函数指针数组:

double add(double, double);
double sub(double, double);
double mul(double, double);
double div(double, double);

double (*oper_func[])(double, double) = {
    add, sub, mul, div, ....
}

double eval(double a, double b, int op, double (*oper_func[])(double, double))
{
    double r;
    r = oper_func[op](a, b);
    return r;
}