C 语言函数指针

2025年7月25日 | 阅读 8 分钟

在 C 语言中,函数指针是指向函数的指针,它存储函数的地址,因此函数可以作为参数传递并动态调用。它在回调函数、事件驱动程序和多态性等方法中非常有用。

正如我们所知,我们可以创建任何数据类型的指针,例如 int、char 和 float。我们也可以创建指向函数的指针。函数的代码总是驻留在内存中,这意味着函数具有某个地址。我们可以使用函数指针来获取内存的地址。

函数指针的简单示例

让我们举一个例子来说明 C 语言中的函数指针。

示例

编译并运行

输出

Address of main() function is 0x5aa2c1954149 

说明

在上面的输出中,我们注意到 main() 函数具有某个地址。因此,我们得出结论,每个函数都有一个地址。

函数指针的声明

C 编程语言 中,函数指针用于存储函数的地址,并可用于间接调用函数。如果我们想声明具有地址的函数,我们可以创建可以包含这些地址的指针。

函数指针的语法

例如

说明

在上面的声明中,*ip 是一个指针,它指向一个返回 int 值并接受整数作为参数的函数。

浮点数指针的语法

说明

在上面的声明中,*fp 是一个指针,它指向一个返回 float 值并接受 float 作为参数的函数。

我们可以观察到,函数声明与函数指针声明类似,只是在指针前面加上了一个“*”。因此,在上面的声明中,fp 被声明为一个函数而不是指针。

到目前为止,我们已经学会了如何声明函数指针。我们的下一步是将函数的地址分配给函数指针。

在上面的声明中,“fp”指针包含“func”函数的地址。

初始化

在 C 编程中,通过提供函数的地址来分配函数指针。

我们也可以省略地址运算符,因为函数名本身就是一个常量函数指针。

必须将函数绑定到与指针声明中声明的签名相同的签名。否则,编译器将显示类型不匹配的错误。

通过函数指针调用函数

我们已经知道如何以常规方式调用函数。现在,我们将学习如何使用函数指针调用函数。

假设我们声明了如下函数

使用常规方式调用上述函数如下

使用函数指针调用函数如下

通过函数名或函数指针调用函数的效果是相同的。如果我们使用函数指针,我们可以省略解引用运算符,就像我们在第二种情况中所做的那样。但是,我们仍然使用解引用运算符,因为它向用户清楚地表明我们正在使用函数指针。

C 语言函数指针示例

让我们举一个例子来说明 C 语言中的函数指针。

示例

编译并运行

输出

Enter the values of a and b : 5
26
Value after addition is : 31

说明

在此示例中,我们演示了使用函数指针调用 add() 函数。在这里,我们使用了存储 add 地址的指针 ip,并通过 (*ip)(a, b) 间接调用函数来执行加法。

在结构中模拟成员函数

我们可以在 结构 中定义数据成员,但不能在其中声明函数。但是,我们可以声明函数指针,这些函数指针又可用于调用指定的函数。

示例

编译并运行

输出

Circle Radius: 6.00
Circle Area: 113.10 

说明

在此示例中,我们声明了一个 Circle 结构,其中包含一个 float 半径和函数指针,用于模拟面向对象的行为,如方法。之后,实现了 setRadius、getArea 和 display 函数来设置半径、计算面积和显示半径。initCircle 函数初始化一个 Circle 对象并设置其函数指针。在 main 函数中,创建并初始化了一个 Circle 对象,将半径设置为 6,显示详细信息,并显示面积。

将函数的地址作为参数传递给另一个函数

我们可以像发送其他参数给函数一样,将函数的地址作为参数传递给其他函数。让我们通过一个例子来理解。

示例

编译并运行

输出

Function1 is called
Function2 is called  

说明

在此示例中,我们创建了两个函数,即 func1() 和 func2()。func1() 函数包含函数指针作为参数。在 main() 方法中,调用 func1() 方法,我们将 func2 的地址传递给它。当调用 func1() 函数时,“ptr”包含“func2”的地址。在 func1() 函数内部,我们通过解引用指针“ptr”来调用 func2() 函数,因为它包含 func2 的地址。

函数指针数组

在 C 编程中,函数指针用于我们事先不知道将调用哪个函数的应用程序。在函数指针数组中,数组存储不同函数的地址,并将根据索引号调用相应的函数。

函数指针数组示例

让我们举一个例子来说明 C 语言中的函数指针数组。

示例

编译并运行

输出

Enter the values of x and y : 5
7

Sum of two values is : 12.000000
Difference of two values is : -2.000000
Multiplication of two values is : 35.000000
Division of two values is : 0.714286

说明

在此示例中,我们创建了一个函数指针数组,其中包含四个函数的地址。将函数地址存储在函数指针数组中后,我们通过函数指针调用函数。

带 void 指针的函数

在 C 编程中,当我们要声明函数时,会使用 void 指针 (void*)。我们有一个 void* 返回类型,允许返回任何类型。但是,函数不能返回 void* 并期望在没有显式转换的情况下自动将其转换为任何类型。

如果我们将数据传递给函数,它不应该被修改,并且参数可以声明为 const void*,这可以防止数据被意外更改。

带 void 指针的函数示例

让我们举一个例子来说明 C 语言中带 void 指针的函数。

示例

编译并运行

输出

Square of 9 is 81 

说明

在此示例中,我们创建了一个名为 square 的函数,它接受一个 const void* 指针,将其转换为 int*,并返回它指向的整数值的平方。在 main() 函数中,它在整数 n 的地址上调用 square 并打印平方值。它演示了如何使用 void* 使通用函数能够处理整数。

结论

总而言之,C 语言的函数指针通过存储函数的地址来实现动态函数调用。它们提供了更通用和模块化的代码,例如使用结构模拟面向对象编程、将函数作为参数传递以及控制函数指针数组以实现动态函数确定。void* 指针在函数内的应用有助于开发可以处理各种 数据类型 的通用函数。

C 函数指针选择题

1) C 语言中的函数指针存储什么?

  1. 函数的内存地址
  2. 数据值
  3. 变量地址
  4. 以上都不是

答案: a) 函数的内存地址


2) 在 C 语言中,将 void* 指针用作函数参数的目的是什么?

  1. 仅指向整数
  2. 通用地接受任何数据类型
  3. 仅指向 void 类型变量
  4. 限制函数输入类型

答案: b) 通用地接受任何数据类型


3) 如果将函数指针分配给具有不同签名的函数,会发生什么?

  1. 它工作得很好
  2. 程序立即崩溃
  3. 编译器显示类型不匹配错误
  4. 函数指针忽略不匹配

答案: c) 编译器显示类型不匹配错误


4) 在通过函数指针调用函数时,可以省略哪个运算符?

  1. 地址运算符 (&)
  2. 解引用运算符 (*)
  3. 成员访问运算符 (->)
  4. 以上都不是

答案: b) 解引用运算符 (*)


5) 如何将函数作为参数传递给另一个函数?

  1. 直接传递函数名
  2. 通过函数指针传递函数的地址
  3. 这是不可能的
  4. a 和 b 都是

答案: d) a 和 b 都是


下一个主题动态内存分配