Skip to content

LV070-函数指针

为了汇总,这里需要使用函数的概念,函数的详情可以看下一章。

一、函数指针简介

如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码 分配一段存储空间,这段存储空间的首地址称为这个函数的地址函数名表示的就是这个地址。通过指针的概念,我们知道既然是地址,那么就可以定义一个指针变量来存放,这个 指针变量 就叫作函数指针变量,简称 函数指针

1. 怎么声明

1.1 基本格式

c
<数据类型> (*<函数指针名称>) (<参数说明列表>);
数据类型 函数指针所指向的函数的返回值类型
(*<函数指针名称>)*说明为指针()不可缺省,表明为函数的指针
参数说明列表 应该与函数指针所指向的函数的形参说明保持一致

【注意】指向函数的指针变量没有 ++ 和 -- 运算

1.2 声明示例

例如:

c
int (*p)(int, int);

这个语句定义了一个指向函数的指针变量 p :

(1)它是一个 指针变量,所以要有一个 * ,即( *p );

(2)前面的 int 表示这个指针变量可以 指向返回值类型为 int 型的函数

(3)括号中的两个 int 表示这个指针变量可以 指向有两个参数且都是 int 型的函数

所以总体来说,这个语句的意思就是:定义了一个指针变量 p ,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。 p 的类型为 int (*)(int,int) 。

2. 怎么使用

2.1 初始化

前边需要有一个函数的声明:

c
int sum(int a, int b); /* 函数声明 */
初始化写法 等价写法(赋值)
int (*p)(int, int) = sum; int (*p)(int, int);
p = sum;

2.2 调用

c
[ <变量名> = ] (*<函数指针名称>)(<实际传入参数说明列表>);

例如:

c
/* 提前定义的函数 */
int sum(int a, int b); /* 函数声明 */
/* --------------------------------------------------  */
/* 主程序中函数指针的操作 */
int (*p)(int, int) = sum;  /* 定义一个函数指针 */
printf("a=%d,b=%d,(*p)(a, b)=%d\n", a, b, (*p)(a, b));

/* --------------------------------------------------  */
/* 或者 */
int c = 0;
int (*p)(int, int) = sum;  /* 定义一个函数指针 */
c = (*p)(a, b);
printf("a=%d,b=%d,c=%d\n", a, b, c);

二、存储空间?

我们写一个实例看看:

c
#include <stdio.h>

int sum(int a, int b); /* 函数声明 */

int main(int argc, char *argv[])
{
    int a = 3;
    int b = 2;
    int c = 0;

    int (*p)(int, int) = sum;  /* 定义一个函数指针 */
    c = (*p)(a, b);
    
    printf("a=%d,b=%d,c=%d\n", a, b, c);
    printf("&a=%p,&b=%p,&c=%p\n", &a, &b,&c);
    printf("&sum=%p,p=%p,&p=%p\n", sum, p, &p);

    return 0;
}

int sum(int a, int b)
{
    return (a + b);
}

这个其实也没啥好说的,函数名就是个地址,直接把地址赋给函数指针,和前面普通指针的用法是一样的,可以看到下面的打印信息:

image-20260227153918916

三、函数指针类型

1. 定义格式

上边我们已经知道了可以按照下边的形式定义一个函数指针:

c
<数据类型> (*<函数指针名称>) (<参数说明列表>);

可是当参数列表中参数很多的时候,就显得很麻烦,这个时候我们可以借助 typedef 来定义一个函数指针类型:

c
typedef <数据类型> (*<函数指针名称>) (<参数说明列表>);

2. 使用实例

c
#include <stdio.h>

typedef int (*MyFunc)(int, char);

int func1(int a, char b);
int func2(int a, char b);

int main(int argc, char *argv[])
{
	int (*p)(int, char);/* 定义一个可以指向带有int和char类型参数且返回值为int类型的函数指针变量 */
	MyFunc pfunc;       /* 与上边的含义相同 */

	p = func1;
	printf("func1 return:%d\n", (*p)(5, 'a'));
	p = func2;
	printf("func1 return:%d\n\n", (*p)(6, 'b'));

	pfunc = func1;
	printf("func1 return:%d\n", (*pfunc)(5, 'a'));
	pfunc = func2;
	printf("func1 return:%d\n", (*pfunc)(6, 'b'));
	return 0;
}

int func1(int a, char b)
{
	printf("func1:a = %d, b = %c\n", a, b);
	return 1;
}

int func2(int a, char b)
{
	printf("func2:a = %d, b = %c\n", a, b);
	return 2;
}

在终端执行以下命令编译程序:

shell
gcc test.c -Wall # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

shell
func1:a = 5, b = a
func1 return:1
func2:a = 6, b = b
func1 return:2

func1:a = 5, b = a
func1 return:1
func2:a = 6, b = b
func1 return:2

可见两种定义其实是完全一致的。

四、函数指针数组

6.1 定义

函数指针数组是一个保存若干个函数名的数组,一般形式如下:

c
<数据类型> (*<函数指针数组名称> [<大小>] )(<参数说明列表> );

其中,<大小> 是指函数指针数组元数的个数,其它同普通的函数指针。

例如:

c
int (*pFunction[3])(int, int);

以上语句定义了一个指针数组 pFunction ,该指针数组的元素都是 int 型函数指针,可以指向返回值类型为 int 型,且有两个整型参数的函数。

6.2 使用示例

c
#include <stdio.h>

typedef int (*MyFunc)(int, char);

int func1(int a, char b);
int func2(int a, char b);

int main(int argc, char *argv[])
{
	int (*p[2])(int, char); /* 定义一个可以指向带有int和char类型参数且返回值为int类型的函数指针数组 */
	MyFunc pfunc[2];        /* 定义一个可以指向带有int和char类型参数且返回值为int类型的函数指针数组 */

	p[0] = func1;
	p[1] = func2;
	printf("func1 return:%d\n", (*p[0])(5, 'a'));
	printf("func2 return:%d\n\n", (*p[1])(6, 'b'));

	pfunc[0] = func1;
	pfunc[1] = func2;
	printf("func1 return:%d\n", (*pfunc[0])(7, 'c'));
	printf("func2 return:%d\n", (*pfunc[1])(8, 'd'));
	return 0;
}

int func1(int a, char b)
{
	printf("func1:a = %d, b = %c\n", a, b);
	return 1;
}

int func2(int a, char b)
{
	printf("func2:a = %d, b = %c\n", a, b);
	return 2;
}

在终端执行以下命令编译程序:

shell
gcc test.c -Wall # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

shell
func1:a = 5, b = a
func1 return:1
func2:a = 6, b = b
func2 return:2

func1:a = 7, b = c
func1 return:1
func2:a = 8, b = d
func2 return:2