函数指针的声明
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
实例1
#include <stdio.h>
typedef int (*fun_t)(int, int);
int sum(int num1, int num2)
{
return num1 + num2;
}
int main()
{
fun_t p;
p = sum;
int a = 3;
int b= -4;
printf("%d\n", p(a, b));
}
实例2
#include <stdio.h>
int max(int num1, int num2)
{
return num1 + num2;
}
int main()
{
int (*p)(int, int);
p = max;
int a = 3;
int b= -4;
printf("%d\n", p(a, b));
}
函数指针数组
#include <stdio.h>
typedef int (*fun_t)(int, int);
int sum(int num1, int num2)
{
return num1 + num2;
}
int max(int num1, int num2)
{
return num1 > num2 ? num1 : num2;
}
int main()
{
fun_t p[2];
p[0] = sum;
p[1] = max;
int a = 3;
int b= -4;
printf("%d\n", p[0](a, b));
printf("%d\n", p[1](a, b));
}
对比实例1与实例2,发现实例1是用typedef
来定义一个函数指针类型,然后在主函数中定义该函数指针类型的指针变量;而实例2是直接定义一个函数指针。在这里可以分析一下函数指针与指针的关系。
int p(int, int);
从p开始,p先与()结合,说明p是一个函数,有2个int类型的函数形式参数,然后与左边的int结合,说明该函数返回的是int类型的数据。int (*p)(int, int);
从p开始,p先与*结合,说明p是一个指针,接着与()结合,说明指针指向的是一个函数,然后再与最右边()里的结合, 说明函数有2个int型的参数, 再与最左边的int结合, 说明该函数返回的是int类型的数据, 所以p是一个指向有2个int类型参数且返回类型为int型的函数的指针。int (*p(int, int))[4];
从p开始,p先与()结合,说明p是一个函数,有2个int类型的函数形式参数,然后与p左边的*结合,说明函数返回的是一个指针,然后与[]结合,说明指针指向的一个数组,数组的元素有4个,然后与int结合,说明数组的元素是int类型的数据,所以p是一个参数为2个int类型的数据且返回一个由4个int类型的数据组成的数组的指针变量的函数。
实例3
将一个二维数组的每个元素都偏移num
int (*func(int num))[4]
{
static int buff[3][4] = {0};
for(int i = 0, j = 0; i < 3; i++)
for(j = 0; j < 4; j++)
*(*(buff + i) + j) += num;
return buff;
}
一般用typedef
来定义新类型,这样方便理解
typedef int (*arr)[4];
arr func(int num)
{
static int buff[3][4] = {0};
for(int i = 0, j = 0; i < 3; i++)
for(j = 0; j < 4; j++)
*(*(buff + i) + j) += num;
return buff;
}
-
int (*(*p)(int, int))[4]
从p开始,p先与*结合,说明p是一个指针,然后与()结合,说明指针指向的是一个函数,同时函数有2个int类型的参数,然后与*结合,说明函数返回的是一个指针,然后与[]结合,说明指针指向的是一个数组,元素个数为4,然后与int结合数组的元素类型是int,所以p是一个指向有2个int类型的参数且返回一个指向由4个int类型数据组成的数组的指针的函数。 -
int *(*p(int, int))[4];
从p开始,p先与()结合,说明p是一个函数,有2个int类型的函数形式参数,然后与p左边的*结合,说明函数返回的是一个指针,然后与[]结合,说明指针指向的一个数组,数组的元素有4个,然后与*结合,说明数组元素的类型是指针,然后与int结合,说明指针指向的是int类型的数据,所以p是一个参数为2个int类型的数据且返回一个指向由int类型指针变量组成的数组的指针变量的函数。
C 语言规定函数名会被转换为指向这个函数的指针
#include <stdio.h>
typedef int (*fun_t)(int, int);
int sum(int num1, int num2)
{
return num1 + num2;
}
int main()
{
fun_t p;
p = sum;
int a = 3;
int b= -4;
printf("p(a, b) = %d\n", p(a, b));
printf("*p(a, b) = %d\n", (*p)(a, b));
printf("(*(&p))(a, b) = %d\n", (*(&p))(a, b));
printf("sum(a, b) = %d\n", sum(a, b));
printf("*sum(a, b) = %d\n", (*sum)(a, b));
printf("%p\n", sum);
printf("%p\n", &sum);
printf("%p\n", *sum);
}
/*
输出结果
p(a, b) = -1
*p(a, b) = -1
(*(&p))(a, b) = -1
sum(a, b) = -1
*sum(a, b) = -1
0000000000401550
0000000000401550
0000000000401550
*/
这里的玄学就是 *sum为什么能和上面两个之前介绍过的输出一样的值。
首先来看函数名 sum,是一个符号用来标识一个函数的入口地址,在使用中函数名会被转换为指向这个函数的指针,指针的值就是函数的入口地址,&sum:显示获取函数的地址。*sum可以认为由于 sum已经被转换成了函数指针, 指向这个函数,所以 *sum就是取这个指针所指向的函数名,而又根据函数名会被转换指向该函数的指针的规则,这个函数也转变成了一个指针,所以 *sum最终也是一个指向函数 sum的指针。也就是说:*sum–> *(&sum) --> sum–> &sum。