一:实质理解和用法
1.1 函数指针的实质 (还是指针变量)
(1)函数指针的实质还是指针,还是指针变量。占4个字节(在32位系统中所有指针都是4字节,64位就是8个字节)
(2)函数指针、数组指针、普通指针之间并没有本质区别,区别在于指针指向的东西是什么
(3)函数的实质其实是一段代码,这一段代码在内存中是连续分布的(一个函数的大括号括起来的所有语句将来编译出来生成的可执行程序是连续的),所以对于函数来说很关键的就是函数中的第一句代码的地址,这个地址就是所谓的函数地址,在C语言中用函数名这个符号来表示。
(4)结合函数的实质,函数指针其实就是一个普通变量,这个普通变量的类型是函数指针变量类型,它的值就是某个函数的地址(也就是它的函数名这个符号在编译器中对应的值)
(5)用画图的方法来理解函数指针
譬如我们定义一个char类型的变量,编译器自动给分配了一个字节的内存空间,它的地址可能是0x40000000.那我们再定义一个char 类型的指针变量编译器也给它分配了一个内存空间0x30000000,但是我们把它和char类型的普通变量给绑定起来,意思就是说我们给指针变量里存放了0x4000000这个地址我们可以通过访问这个指针变量的值去访问char类型的指针变量
那我们定义一个函数指针里面存放的值是func这个符号对应的地址0xA0000000,那是不是就可以通过这个函数指针去访问func函数了
1.2 函数指针的书写和分析方法
(1)C语言本身是强类型语言(每一个变量都有自己的变量类型),编译器可以帮我们做严格的类型检查。 (譬如定义一个int类型的变量但是赋值为3.14159那么编译器 就会报错提醒类型不匹配)
(2)所有的指针变量类型其实本质都是一样的,但是为什么在C语言中要去区分它们?写法不一样呢?(譬如int类型指针就写作int *p;数组指针就写作int (*p[5]; 函数指针就写的更复杂)
原因是因为这样可以提供给编译器更多的信息,让它给我们进行类型检查
示例:
#include <stdio.h>
int main(void)
{
int a[5]; //定义一个数组数组里面有五个int类型的元素
int *p; //定义一个int类型的
p = a; // 运行编译器不会报错类型匹配
//p = &a; //运行编译器报错,p是 int * 类型的 而&a是int (*p)[5];
int (*p1)[5];
p1 = &a; // p1类型是int (*)[5] &a 也是 int (*)[5]
retrun 0;
}
(3)假设我们有个函数是:void func(void);对应的函数指针:void (*pfunc)(void);
类型是:void (*) (void);
示例:
#include <stdio.h>
void func(void)
{
printf("i am func");
}
int main(void)
{
void (*pfunc) (void); //定义一个函数指针
pfunc = func; //把函数地址赋给函数指针
pfunc(); //用函数指针来调用该函数
return 0;
}
(4)函数名最大的区别就是:函数名做右值时加不加&效果和意义都是一样的,但是数组名加不加&意义是不一样的
(5)复杂的函数指针示例:譬如函数是strcpy函数 (char *strcpy(char *dest,const char *src);), 对应的函数指针是 char *(*pfunc)(char *dest,const char *src);
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[5] = 0;
char a[5] = {0};
char *(*pfunc) (char *,const char *);
pfunc = strcpy;
pfunc(a,"abc");
printf("%S\n",a);
}
1.3 typedef关键字的用法
(1)tepedef是C语言中的一个关键字,作用是用来定义(或者说重命名类型)
(2)C语言中的类型一共有两种,一种是编译器定义的原生类型(譬如int 、 double之类的);另一种是用户自定义类型,不是语言自带而是程序员自己定义的(比如数组类型、结构体类型、函数类型......)
(3)上次提到的数组指针和指针数组和本次的函数指针都属于用户自定义类型
(4)由于每次自定义类型太长了,用起来不方便,所以用typedef给它重命名一个较短的名字
(5)注意:typedef是给类型重命名,也就是说 typedef加工出来的都是模型,而不是变量
#include <stdio.h>
typedef char* (*pType) (char *,const char *); //这句重新定义了一种类型,这个类型名字叫做
//pType,类型是:char* (*) (char
//*,const char *);
int main(void)
{
char* (*p1) (char *,const char *); // 定义了一个函数指针
char* (*p2) (char *,const char *); //
pType p3; //等效于char* (*p1) (char *,const char *);
pType p4;
p3 = p1; //将p1赋值给p3(现在p1是个野指针),用编译器来验
//证是否正确,编译器不报错不警告,编译成功说明理
//解无误 (没有实在的意义只是用来测试编译器对
//两个指针的类型的判断是不是一样的)
retrun ;
}