墙,无处不在。即使在网上,我们也被GFW重重围住。在互联网中,我们犹如次等国民,难以自由地和外界交流。google被墙,facebook,twitter被墙,GitHub被墙,网友们纷纷抗议,开复老师的一条微博得到广大的支持。终于Github被解封了。虽然毕业半年了,进入公司后坚持学习技术的心始终未变。基础差也毫无畏惧,奋力追赶。
第一部分 什么是函数指针
1.1 函数指针概念
1.2 函数指针与指针函数,数组指针与指针数组
1.3 函数指针的作用
第二部分 函数指针的初始化及使用
2.1 初始化函数指针
2.2 函数名究竟是什么
#include <stdio.h>
int test(void );
int main(void )
{
printf( " test=%p\n",test);
printf( "&test=%p\n",&test);
printf( "*test=%p\n",*test);
return 0;
}
int test(void )
{
printf( "test invoked!");
return 0;
}
|
2.3typedef可以用于定义函数指针类型
要说明一下,对于typedef int (*ptf) (double*,char); 注意不要用#define的思维来看待typedef,如果用 #define的思维来看的话会以为 (*ptf)(double*, char)是int的别名,但这样的别名看起来好像又不是合法的名字,于是会处于迷茫状态。实际上,上面的语句把 ptf定义为一种函数指针类型的别名,它和函数指针类型 int (*) (double*, char);等价,也就是说ptf现在也是一种类型。
下面分析一个函数指针和指针函数结合的例子:
void (*signal (int sig, void (*func) (intsiga)) ) ( int siga );
看上去确实有些复杂,让我们来分析。现在要分析的是 signal,因为紧邻 signal的是优先级最高的括号,首先与括号结合,所以 signal为一个函数,括号内为 signal的两个形参,一个为 int型,一个为指向函数的指针。接下来从向左看, *表示指向某对象的指针,它所处的位置表明它是 signal的返回值类型,现在可以把已经分析过的 signal整体去掉,得到 void (*) ( int siga ),很清晰了吧。又是一个函数指针,这个指针与 signal形参表中的第二个参数类型一样,都是指向接受一个 int型形参且不返回任何值的函数的指针。同样地,用 typedef可以将这个声明简化:
typedef void (*p_sig) (int);
p_sig signal(int sig, p_sig func);
这个signal 函数是C语言的库函数,在 signal.h中定义,用来处理系统中产生的信号,是 UNIX/Linux编程中经常用到的一个函数,所以在此单独拿出来讲解。
2.4 函数指针数组
还有一种较为常用的关于函数指针的用法——函数指针数组。假设现在有一个文件处理程序,通过一个菜单按钮来选择相应的操作 (打开文件,读文件,写文件,关闭文件 )。这些操作都实现为函数且类型相同,分别为:
void open( );
void read( );
void write( );
void close( );
现在定义一个函数指针类型的别名
PF: typedef void (*PF) ( );
把以上4种操作取地址放入一个数组中,得到:
PF file_options[ ] = {
&open,
&read,
&write,
&close
};
这个数组中的元素都是指向不接受参数且不返回任何值的函数的指针,因此这是一个函数指针数组。接下来,定义一个函数指针类型的指针 action并初始化为函数指针数组的第一个元素: PF* action = file_options;,如果不好理解,可以类比一下 int ia[4] = {0, 1, 2, 3}; int *ip = ia;,这里PF 相当于int,这样应该比较好懂了。通过对指针 action进行下标操作可以调用数组中的任一操作,如: action[2]( )会调用 write操作,以此类推。在实际中,指针 action可以和鼠标或者其他 GUI对象相关联,以达到相应的目的。
2.5 复杂的函数指针声明