C语言指针(四)

大家好,我是小张同学,今天总结函数指针。

目录

1. 函数指针

1.1 函数指针引入

1.2 函数指针使用

2. typedef函数指针

3. 回调函数


1. 函数指针

1.1 函数指针引入

所谓函数指针就是一个指向函数的指针变量。所以函数指针是一个指针,不是函数,就像int *n = &a,指针变量 n 存放的是 a 的地址,那么函数指针存放的就是一个函数的地址。

更详细点说,如果在程序中定义了一个函数,在编译时系统会为这个函数分配一段存储空间,这段存储空间的首地址就是这个函数的地址,并且这个地址可以用函数名表示,既然是地址,我们就可以定义一个指针变量来存放,这个指针变量就是函数指针

举个例子:

int function(int x, int y);
int(*pFunction)(int x, int y) = &function;  //注意这里 *和pFunction是用括号括起来的
int(*pFunction)(int x, int y) = function;   //初始化时,&操作符是可选的,因为函数名本身就是函数的地址

以上代码定义了一个函数指针变量 pFunction,并将其初始化为指向函数 function,首先 (*pFunction)表明这是一个指针变量,第一个 int 表示这个指针可以指向返回值为 int 类型的函数,后面括号中的两个 int 表示这个指针可以指向有两个 int 参数的函数,所以,合起来就是这个指针变量可以指向一个返回值类型为 int 型,且有两个int 型参数的函数。

所以函数指针的定义方式就是 函数返回值类型 (*指针变量名) (函数参数列表)

既然pFunction是一个变量,那么它的类型是什么呢,把变量名去掉,就是它的类型,所以pFunction的类型为 int(*)(int,int)

指针函数,指的是函数的返回值是一个指针,比如我定义一个函数,这个函数返回的类型是一个 int*,如下:

int *p(int a, int b);  //注意这里 *和p之间是没有括号的

1.2 函数指针使用

在函数指针被声明并且初始化之后,我们可以使用三种方式调用函数:

int function(int x, int y)                       //定义一个函数
{
    printf("x = %d, y = %d\n", x, y);
    return 0;
}
int (*pFunction)(int x, int y) = function;      //定义一个函数指针,并用function函数的地址将其初始化

int x = 1;
int y = 2;
function(x, y);                        
(*pFunction)(x, y);                    //通过函数指针调用function函数
pFunction(x, y);                       //通过函数指针调用function函数

第一种:简单地使用函数名字调用,但其实在执行地过程中,函数名function首先被转换为一个函数指针,然后执行始于这个地址地代码。

第二种:*pFunction把函数指针转换为一个函数名,这个转换实际并不需要,因为编译器在执行过程中又会把它转换回去。

第三种:直接使用pFunction,编译器需要的是一个函数指针。通常使用第三种方式。

2. typedef函数指针

typedef int (*p)(int x, int y);

以上代码的含义是:

p是一个类型别名,也就是将 void(*)(int,int) 这个类型,定义了一个别名p。

举个例子:

typedef int (*p)(int x, int y);    //为 int(*)(int, int)类型定义一个别名p
p pFunction;                       //定义一个p类型的变量pFunction
int function(int x, int y)         //定义一个函数
{
    printf("x = %d, y = %d\n", x, y);
    return 0;
}

void main()
{
    pFunction = function;         //将function函数的首地址赋给变量pFunction
    pFunction(2, 3);              //通过函数指针调用函数
}

3. 回调函数

函数指针更重要的意义在于回调函数。

让我们来构造一个场景,希望有一个函数可以在整数链表中查找一个值,如下:

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

上面这个函数只适用于 value 值为 int 类型的链表,如果我们需要在一个 value 值为 char 类型的链表中查找,那就需要再写另外一个新函数,新函数和上面的函数绝大部分代码都相同,只是 value 类型不同。

一种更为通用的方法是让查找函数 search_list 与类型无关,这样函数就可以对任何类型的值进行比较,这就需要用到函数指针了。需要编写一个比较函数,然后将这个比较函数的指针作为参数传递给查找函数 search_list,如下:

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

我看上面 search_list传入的函数指针不顺眼,来用上刚刚说的 typedef 试试,于是改成了下面这样:

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

如果需要在整数链表中查找,就编写一个比较函数 compare_ints,如下:

int compare_ints(void const *a, void const *b)
{
    if(*(int*)a == *(int*)b)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}
//注意这里的强制类型转换

 这个比较函数就要像下面这样使用,将其地址作为参数传到search_list函数中:

desired_node = search_list(root, &desired_value, compare_ints);

我们上面使用的技巧就是回调函数,回调函数就是将一个函数指针作为参数传递给其他函数,后者将"回调"这个函数。

如果希望在字符串链表中查找,以下代码就可以实现:

desired_node = search_list(root, "desired_value", strcmp);

于是函数指针就基本介绍完了,我们下期接着讲指针

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值