在内存中函数的存放也是一段连续的内存,函数名就是指向改内存中的首地址,所以也可以将这个函数的首地址赋给一个指针变量,这样通过指针变量就可以访问改函数。
那么为什么要通过指针来访问函数呢?下面通过一个简单的例子来演示一下。
int (*fun)(int m,int n);
int Add(int x,int y)
{
return x + y;
}
int Sub(int x,int y)
{
return x - y;
}
int Mul(int x,int y)
{
return x * y;
}
int Div(int x,int y)
{
return x / y;
}
int main()
{
int ret = 0;
int i = 0;
for(i=0; i<4; i++)
{
switch(i)
{
case 0:
fun = Add;
break;
case 1:
fun = Sub;
break;
case 2:
fun = Mul;
break;
case 3:
fun = Div;
break;
}
ret = fun(10,5);
printf("%d\r\n",ret);
}
system("pause");
return 0;
}
定义了加、减、乘、除四个函数,在for循环中依次将这四个函数传递给函数指针,分别计算两个整数的加、减、乘、除的结果。代码执行结果如下:
看到这里就会有个疑问?为什么非要用函数指针来实现呢?直接在switch语句中调用不同的函数不是依然能实现这个过程吗?对于这个例子来讲,是没有必要非要用指针啦传递函数。完全可以直接调用具体函数来实现。
上面的例子中由于所有函数的功能都是自己实现的,所以直接调用和通过指针调用没有多大的区别,但是在很多情况下,函数需要用户自己去实现,那么此时使用指针的优势就比较明显了。比如下面的例子:
int values[] = { 88, 56, 100, 2, 25 };
int up (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int down (const void * a, const void * b)
{
return ( *(int*)b - *(int*)a );
}
int main()
{
int n;
puts("排序之前的列表:");
for( n = 0 ; n < 5; n++ )
{
printf("%d ", values[n]);
}
puts("\n升序排列");
qsort(values, 5, sizeof(int), up);
puts("排序之后的列表:");
for( n = 0 ; n < 5; n++ )
{
printf("%d ", values[n]);
}
puts("\n降序排列");
qsort(values, 5, sizeof(int), down);
puts("排序之后的列表:");
for( n = 0 ; n < 5; n++ )
{
printf("%d ", values[n]);
}
system("pause");
return 0;
}
这里使用了C库中的排序函数,函数原型如下:
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
参数:
base -- 指向要排序的数组的第一个元素的指针。
nitems -- 由 base 指向的数组中元素的个数。
size -- 数组中每个元素的大小,以字节为单位。
compar -- 用来比较两个元素的函数。
这里最后一个比较函数就需要用户自己去实现,根据用户的提供的函数,排序函数就可以自动的去选择是升序排列还是降序排列。如果给qsort()函数里面传递的是up()函数,那么数组中的数据就会升序排列,如果传递的是down()函数,那么数组中的数据就降序排列。
在这个例子中qsort()函数是C库函数,这个函数的最后一个参数也是一个函数,这个函数必须由用户来提供。那么此时用指针来传递函数是最方便的,因为用指针传递函数的时候,函数名可以由用户自己定义。这样qsort()函数的通用性就会非常好了。如果要传递的函数名称和参数都必须是固定的话,在使用起来就有很大的局限性。
所以使用指向函数的指针来传递参数时,可以更好的封装函数,提高函数的通用性和易读性。
下面详细的说一下,如何将一个函数替换为指针。
首先看一个函数原型:
int Add(int x,int y);
Add()函数类型是 “带int int类型参数,返回类型是int型的函数”,将它改写为指针pf指向该函数类型:
int (*pf)(int x,int y);
替换的方式为 将函数名改为 ( * pf) ,其他部分保持不变。这样就将函数替换为指向指针的函数了,这里一定要加上小括号,如果不加小括号的话就会变成
int *pf(int x,int y);
由于小括号的优先级高,所以pf就会先和后面的小括号结合,变成 pf(int x,int y),函数的返回类型就变成了 int * ,这样含义完全就变了,变成了 函数pf()有两个参数,它的返回值为 int 指针类型。所以这里一定要加上小括号。
其中参数列表中可以会将变量省略,只写变量的类型。上面指向函数的指针可以简写为:
int (*pf)(int ,int );
由于函数名指向了内存中函数的起始地址,所以要将函数的地址可以直接使用下面的方法:
pf = Add;
将函数Add的首地址直接赋值给指针pf,这样通过指针pf就可以访问Add()函数了。
所以上面的函数 Add(x,y) 可以直接替换为 (*pf)(x,y) ,相当于 Add == (*pf)。但是通过上面第一个例子可以发现,使用 pf(x,y)调用函数的时候也是可以正常使用的。虽然 (*pf)(x,y) 和 pf(x,y)这两种调用方式看起来是矛盾的,但是C语言中对于函数指针来说这两种用法都可以,是一样的。
fun = Add;
ret = fun(10,5);
printf("%d\r\n",ret);
fun = Sub;
ret = (*fun)(10,5);
printf("%d\r\n",ret);
通过这两种方式分别调用函数,输出结果如下:
如果要更复杂一点,可以声明一个指针数组,依次存储这4个函数。
typedef int (*fp)(int int);
fp fun[4] = {Add,Sub,Mul,Div};
通过一个函数指针数组可以更方便的调用各个函数。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_20222919/article/details/121221742
内容来源于网络,如有侵权,请联系作者删除!