1.函数指针
1.1什么是函数指针
什么是函数指针变量呢?整型指针变量—>指向整型的指针变量,浮点型指针变量—>指向浮点型的指针变量,那么函数指针变量就是指向函数的指针变量,指向的地址是函数的地址。
函数指针定义形式如下:
#include<stdio.h>
int Add(int x, int y) {
return x + y;
}
int main() {
int (*pf)(int, int) = &Add;
return 0;
}
我们定义一个简单的Add函数,对于指向Add函数地址的指针变量的定义:首先Add返回的类型为int型,所以指针变量返回类型同为int,同时还需要在两侧用括号表示出与Add函数类型同样的形参类型,对于指针的声明,我们需要用括号将 * 与 变量名括起来,防止变量名与旁边的括号先结合。
对于函数指针类型是什么,将指针变量名去掉,得出的就为函数指针类型,如上的函数指针类型就为:
int (*)(int, int)
对于其他的函数之中与上同理,以下给出一些实例:
#include<stdio.h>
char* Print(int x, char y) {
//...
return NULL;
}
int Compare(const void* p1, const void* p2) {
//...
return 0;
}
void menu(double x) {
//...
return;
}
int main() {
void (*pf1)(double) = &menu;
int (*pf2)(const void* p1, const void* p2) = &Compare;
char* (*pf3)(int, char) = &Print;
return 0;
}
1.2函数指针的作用
函数指针方便我们直接调用函数,多了一种调用函数的方法,如下:
如上图可知,对于函数指针的用法可以有两种形式,第一种通过解引用之后在传入参数,第二种不通过解引用直接传入参数。因为由Add函数的调用可知,直接使用函数名传参(函数名为函数首地址),所以对于指针函数的调用,既可以使用解引用之后进行调用,也可以直接进行调用。
1.3函数指针的一些实例
现在通过一些实例来加强我们对函数指针的理解:
第一个例子:
int main() {
(*(void(*)())0)();
return 0;
}
我们来分析一下这个有趣的有关函数指针的代码。 首先我们分析最里面的一个void(*)(),看这样的一个形式,对比我们上面所讲的,不难看出,这是一个返回类型为void型,传入参数为NULL的函数指针类型。然后在这样的一个函数指针类型的外面,有着一个括号括着,并且在一个0的前面:(void(*)())0,一个指针类型加上一个括号在一个数字前面,指针类型在括号里面,表示强制转换为一个地址(指针),这样0就从一个整型转为为了地址,然而当我们把(void(*)())0这个去掉之后,剩下的就为 (*)(),这表示一个函数指针类型,返回的类型为NULL,传入的类型也为NULL。注意:在这样的一个地址前加上了一个 * 号,表示解引用,说明是在解引用一块地址编号为0的地址,所以整体就为一次函数调用!简单来说,就一下几点:
1.把0这个整数值,强制类型转化成一个函数的地址,这个函数没有参数,返回类型为void。
2.调用0地址处的函数
第二个例子:
int main() {
void (*signal(int, void(*)(int)))(int);
return 0;
}
这个函数的理解和以上类似,这里就简要概括了:
1.signal函数是一个函数声明
2.signal函数的第一个参数的类型为int,第二个参数类型为函数指针:viod(*)(int)
这个函数指针指向的函数参数为int,返回类型为viod
2.signal函数的返回类型也为一个函数指针:void(*)(int)
这个函数指针指向的参数为int,返回类型为void。
2.函数指针的简写
简写就是重命名,比如如下:
typedef unsigned int uint;
typedef unsigned short ushort;
这是将unsigned int(short)重命名为uint和ushort,方便编码。
对于函数指针的简写:
typedef int(*)(int, int) pf;
typedef int(*pf)(int, int);
对于以上两种写法,其实只有第二种才是对的,第一种是错的,IDE不能识别。同理,对于指针函数和函数指针的简写都是类似于函数指针的样子:
typedef int(*pfarr)[10]; //数组指针
typedef int* pfARR[10]; //指针数组