附上之前指针数组与数组指针的博客:https://blog.youkuaiyun.com/qq_41078889/article/details/102533019
之前我们了解过数组指针和指针数组,那么现在对于指针函数与函数指针应该很容易区分。
对于int * Fun();和int (*Fun)();我们一眼可以看出来第一个是指针函数第二个是函数指针。
1.指针函数与函数指针
指针函数:一个函数返回值为指针类型的函数,本质就是个函数。
首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。
函数指针:指向函数的指针变量,本质是一个指针变量。
2.指针函数与函数指针的声明
1)指针函数声明
类型关键字 *函数名(参数列表)
int *Fun(int a,int b);
2)函数指针声明
类型关键字 (*函数名)(参数列表)
int (*Fun)(int a,int b);
注意:函数指针在使用时与普通指针一样,需要初始化指向有效地址才能使用,函数指针则指向函数实体的地址,即是函数名称。
3.指针函数的使用
指针函数的使用和一般函数的使用相同,只是返回值是一个指针值,即地址。对于指针函数的返回值,需要注意如下几点。
- 不能返回从栈上分配的内存地址,如局部变量,因为函数结束时,即释放栈内存,此时返回栈上内存地址,相当于野指针。
- 可以返回静态变量(static)、全局变量的地址、从堆上手动分配(malloc/new)的内存地址、通过指针形参所获得的实参的有效地址。
- 返回从堆上手动分配的内存时,注意及时释放(free/delete),否则导致内存泄漏,这种方式会降低程序的可读性和可靠性。
#include<stdio.h>
int *Fun(int x)
{
static int num[] = { 0,1,2,3,4,5,6 };
return &num[x]; //返回一个地址
}
int main()
{
int num;
printf("Please enter the number between 0 and 6: ");
scanf("%d", &num);
printf("\nresult is:");
printf("%d",*Fun(num)); //输出返回地址块中的值
return 0;
}
4.函数指针的使用
在使用函数指针前,必须对函数指针进行初始化指向函数实体。
实例:通过函数指针比较两个数的大小。
#include<stdio.h>
int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int(*func)(int, int); //定义一个指向该函数形式的指针变量
func = max;
int a = 3, b = 4;
int result = (*func)(a, b); //运用指针变量调用函数
printf("max=%d\n", result);
}
5.函数指针的回调用法
函数指针的常见用法就是把函数指针作为参数传递给函数。一个函数通过由运行时决定的指针来调用另一个函数的行为叫做回调(callback)。用户将一个函数指针作为参数传递给其它函数,后者将“回调”用户的函数。这样就可实现通过同一接口实现不同的执行效果(类似C++中的多态性)。
这里有一个简单的函数,它在用一个单链表中查找一个值。它的参数是指向链表第一个节点的指针以及那个需要查找的值。
Node * search_list(Node *node, const int value)
{
while(node != NULL)
{
if(node->value == value)
break;
node = node->link;
}
return node;
}
这个函数看上去简单,但它只适用于整数的链表。如果需要在一个字符串链表查找,就得重新编写一个函数。
呃呃呃,解决方法就是函数指针,调用者编写一个函数,用于比较两个值,然后把指向这个函数的指针作为参数传递给查找函数。然后查找函数调用这个函数来执行值的比较。我们必须修改项函数传递一个指向值的指针而不是值本身。函数有一个void * 形参,用于接收这个参数,然后指向这个值的指针便传递给比较函数。这个修改使字符串和数组对象也可以被使用。使用这种技巧的函数被称为回调函数。
修改后的函数如下:
int compare(void *a, void *b)
{
if(*(int *)a == *(int *)b)
return 0;
else
return 1;
}
Node * search_list(Node *node, void *value, int (*compare)(void *, void *))
{
while(node != NULL)
{
if(compare(&node->value,value) == 0)
break;
node = node->link;
}
return node;
}