函数指针
1.指的是一种特殊的指针类型,该类型指向的是函数
2.由于函数的参数个数及类型不同,因此函数指针类型也就有多种了
void (* pfunc) (int); // --- 这是定义了一个变量pfunc ,该变量为函数指针类型。
typedef void (* func)(int); // --- 这相当于定义了一个新类型func ,该类型为函数指针(且该函数指针返回值为void,有一个int参数)
func signal(); //--这表示函数返回值为函数指针(且该函数指针返回值为void,有一个int参数)
void (*signal())(int); //等同上面
void *signal() 和 void (*signal())(int) 区别 //前者函数返回void *类型的指针,后者返回函数指针(且该函数指针返回值为void,有一个int参数)
1. 首先,在C语言中函数是一种function-to-pointer的方式,即对于一个函数,会将其自动转换成指针的类型.如:
CODE:
#include<stdio.h>
void fun()
{
}
int main()
{
printf("%p %p %p/n", &fun, fun, *fun);
return 0;
}
这三个值的结果是一样的. 其实对于最后的那个*fun, 即使前面加上很多个*号, 其结果也不变, 即**fun, ***fun的结果都是一样的. 对于这个问题, 因为之前讲过函数是一种
function-to-pointer方式, 其会自动转换成指针的类型, &fun是该函数的地址, 为指针类型, fun是一个函数, 会转换成其指针类型, 而对于*fun, 由于fun已经变成了指针类型, 指向这个函数, 所以*fun就是取这个地址的函数, 而又根据function-to-pointer, 该函数也转变成了一个指针, 所以以此类推, 这三个值的结果是相同的.
2. 如何调用一个地址上的函数
如果知道了一个函数所在的地址, 可以将其强制转化成某一种类型的函数指针, 然后再根据这个指针去调用这个地址的函数. 如:
CODE:
#include<stdio.h>
void f(int i)
{
printf("i = %d/n", i);
}
int main()
{
unsigned long add;
add = (unsigned long)f;
((void (*)(int))add)(10);
(*(void (*)(int))add)(20); //相同
return 0;
}
使用(void (*)(int))的方式可以将一个地址转换成一个带int参数且没有返回值的函数的指针类型, 然后再去调用, 由于第1点中讲的function-to-pointer, 所以最后两条语句中加与不加那个*号效果都是一样的. 在嵌入式方面经常用到这种方式.
3. 函数指针数组的用法.
有时候需要定义一个数组, 其内容为一系列的函数指针, 然后对其进行调用, 如:
CODE:
#include<stdio.h>
int max(int v1, int v2)
{
return (v1 > v2 ? v1 : v2);
}
int min(int v1, int v2)
{
return (v1 < v2 ? v1 : v2);
}
int sum(int v1, int v2)
{
return (v1 + v2);
}
int main()
{
int (*p[3])(int, int);
p[0] = max;
p[1] = min;
p[2] = sum;
printf("p[0] = %d/n", (p[0])(3, 5));
printf("p[1] = %d/n", (p[1])(4, 6));
printf("p[2] = %d/n", (p[2])(1, 2));
return 0;
}
虽然感觉这种方法有点累赘, 但是也算是一种使用的方式, 所以介绍一下.
4.返回一个指向数组的指针的方式
可以让函数返回一个指向数组的一个指针, 如:
CODE:
#include<stdio.h>
#include<stdlib.h>
int (*p())[10]
{
int (*m)[10];
int i;
m = (int (*)[10])malloc(10 * sizeof(int));
if (m == NULL)
{
printf("malloc error/n");
exit(1);
}
for (i = 0; i < 10; i++)
*(*m+i) = i+1;
return m;
}
int main()
{
int (*a)[10];
int i;
a = p();
for (i = 0; i < 10; i++)
printf("%d ", *(*a+i));
printf("/ndone/n");
return 0;
}
这种方式中,int (*a)[10]是一个指向一维数组的一个指针, 而p()也是返回一个指向一维数组的一个指针.
5.返回一个函数指针的指针
对这个问题, signal()函数是最好的例子,
CODE:
void (*signal (int signo, void (*func)(int)))(int);
很多朋友刚开始看这个函数定义的时候是不太懂, 其实可以一步一步地慢慢看, 我以前是这样分析的, 希望能对大家有用.
int (*p)();
这是一个函数指针, p所指向的函数是一个不带任何参数, 并且返回值为int的一个函数.
int (*fun())();
这个式子与上面式子的区别在于用fun()代替了p,而fun()是一个函数,所以说就可以看成是fun()这个函数执行之后,它的返回值是一个函数指针,这个函数指针(其实就是上面的p)所指向的函数是一个不带任何参数,并且返回值为int的一个函数.所以说对于
CODE:
void (*signal(int signo, void (*fun)(int)))(int);
就可以看成是signal()函数(它自己是带两个参数,一个为整型,一个为函数指针的函数), 而这个signal()函数的返回值也为一个函数指针,这个函数指针指向一个带一个整型参数,并且返回值为void的一个函数.
//最后,看了书以及头文件signal.h,都采用typedef重新定义,才理解得更容易:
typedef void (* func)(int);
func signal(int, func);
signal函数返回的其实是指向以前的信号处理程序的指针, 所以举一个例子来说明返回指向函数的指针的用法,如:
[Copy to clipboard] [ - ]
CODE:
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
void sig_fun2(int signo)
{
printf("in sig_fun2:%d/n", signo);
}
void sig_fun1(int signo)
{
printf("in sig_fun1:%d/n", signo);
}
int main()
{
unsigned long i;
if (signal(SIGUSR1, sig_fun1) == SIG_ERR)
{
printf("signal fun1 error/n");
exit(1);
}
(signal(SIGUSR1, sig_fun2))(30);
printf("done/n");
return 0;
}
6. 使用函数指针作为参数的情况
在函数的参数中, 可能会带有一个函数指针, 这在signal()函数中是出现了的, 另外再写个例子如:
CODE:
#include<stdio.h>
int max(int v1, int v2)
{
return (v1 > v2 ? v1 : v2);
}
int min(int v1, int v2)
{
return (v1 < v2 ? v1 : v2);
}
int sum(int v1, int v2)
{
return (v1 + v2);
}
int fun(int a, int b, int (*call)(int, int))
{
return (call(a, b));
}
int main()
{
printf("max=%d/n", fun(1, 2, max));
printf("min=%d/n", fun(3, 4, min));
printf("sum=%d/n", fun(5, 6, sum));
return 0;
}
其实在很多排序函数中就是使用的这个参数为函数指针的方式来进行调用的.