深入解析C++中函数指针及其数组、typedef关键字用法举例

 更新时间:2025年08月20日 10:23:48   作者:咸鱼_要_翻身  
文章介绍了函数指针的概念、声明与使用,通过实例解析其在信号处理和内存地址调用中的应用,并说明typedef如何简化复杂类型声明,感兴趣的朋友跟随小编一起学习吧

一、函数指针变量的创建

1、什么是函数指针变量?

        类比整型指针和数组指针的概念,我们可以得出:函数指针变量是用来存放函数地址的变量,通过这个地址我们可以调用相应的函数。

2、函数是否有地址?

通过以下测试代码可以验证:

#include <stdio.h>
void test() {
    printf("hehe\n");
}
int main() {
    printf("test: %p\n", test);
    printf("&test: %p\n", &test);
    return 0;
}

输出结果:

        结果表明函数确实有地址,且函数名就是函数的地址,也可以通过&函数名的方式获取函数地址。(重点!!!)

3、创建函数指针变量

函数指针变量的声明语法与数组指针类似:

void test() {
    printf("hehe\n");
}
// 两种等效的函数指针声明方式
void (*pf1)() = &test;
void (*pf2)() = test;
int Add(int x, int y) {
    return x + y;
}
// 函数指针声明,参数名可省略
int (*pf3)(int, int) = Add;
int (*pf4)(int x, int y) = &Add;

4、函数指针类型解析

int (*pf3)(int x, int y)为例:int (*) (int x, int y) 为pf3函数指针变量的类型

二、函数指针变量的使用

通过函数指针调用函数的示例:

#include <stdio.h>
int Add(int x, int y) {
    return x + y;
}
int main() {
    int(*pf)(int, int) = Add;
    // 两种等效的调用方式
    printf("%d\n", (*pf)(2, 3));  // 显式解引用
    printf("%d\n", pf(3, 5));     // 隐式调用
    return 0;
}

输出结果:

三、两段有趣的代码

以下两段有趣的代码出自《C陷阱和缺陷》:

1、解释(*(void (*)())0)();

这段代码的功能是:调用位于内存地址0处的函数

让我们逐步解析:

  • void (*)():这是一个函数指针类型,表示"指向一个没有参数且返回void的函数的指针"。
  • (void (*)())0:将整数值0强制转换为上述函数指针类型。这表示"把地址0当作一个函数的地址"。
  • *(void (*)())0:解引用这个函数指针,得到位于地址0处的函数。
  • (*(void (*)())0)():最后调用这个函数(通过函数指针调用)。

实际意义:这段代码尝试调用内存地址0处的函数。在嵌入式系统中,这可能是调用复位向量或启动代码的方式。但在大多数现代操作系统中,这会引发段错误(segmentation fault),因为地址0通常是被保护的区域。

2、解释void (*signal(int, void(*)(int)))(int);

这是一个函数声明,声明了名为signal的函数。让我们分解它:

  • 最内层:void(*)(int):这是一个函数指针类型,表示"指向一个接受int参数且返回void的函数的指针"。
  • signal(int, void(*)(int)):signal是一个函数,它接受两个参数:一个int、一个上述类型的函数指针
  • 整个声明:void (*signal(int, void(*)(int)))(int):表示signal函数返回一个函数指针,这个指针指向"接受int参数且返回void的函数"。

更易读的写法(使用typedef,下面会讲解):

typedef void (*sighandler_t)(int);  // 定义函数指针类型
sighandler_t signal(int signum, sighandler_t handler);

实际意义:这是Unix/Linux系统中用于设置信号处理器的标准函数声明。它:

  • 接受一个信号编号(int)和一个处理该信号的函数指针
  • 返回之前为该信号设置的处理函数指针

四、typedef关键字

typedef用于类型重命名,可以简化复杂类型的声明。

1、基本用法

typedef unsigned int uint;  // 将unsigned int重命名为uint
typedef int* ptr_t;         // 将int*重命名为ptr_t

2、对于数组指针和函数指针的重命名

新的类型名必须在*的右边:

typedef int(*parr_t)[5];    // 将数组指针类型int(*)[5]重命名为parr_t
typedef void(*pfun_t)(int); // 将函数指针类型void(*)(int)重命名为pfun_t

3、使用typedef简化代码void (*signal(int, void(*)(int)))(int);

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

五、函数指针数组

数组是存放相同类型数据的存储空间。我们已经学过指针数组:

int *arr[10];  // 数组的每个元素是int*

如果要存储函数地址,就需要使用函数指针数组。函数指针数组的定义方式:

int (*parr1[3])();   // 正确:包含3个函数指针的数组,每个指针指向返回int的无参函数

下面是错误用法:

int *parr2[3]();     // 错误:错误语法
int (*)() parr3[3];  // 错误:错误语法

解析parr1

  • parr1先与[]结合,说明它是一个数组
  • 数组的内容是int (*)()类型的函数指针

函数指针数组常用于实现状态机或回调函数机制,是C语言中一种强大的编程技术。

到此这篇关于深入解析C++中函数指针及其数组、typedef关键字用法举例的文章就介绍到这了,更多相关C++函数指针 typedef关键字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于CLion配置visual studio(msvc)和JOM多核编译的问题

    关于CLion配置visual studio(msvc)和JOM多核编译的问题

    这篇文章主要介绍了CLion配置visual studio(msvc)和JOM多核编译,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • OpenCV绘制正多边形的方法

    OpenCV绘制正多边形的方法

    这篇文章主要为大家详细介绍了OpenCV绘制正多边形的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • C++ OpenCV模拟实现微信跳一跳

    C++ OpenCV模拟实现微信跳一跳

    这篇文章主要介绍了使用C++和OpenCV模拟实现微信跳一跳功能,本文图文并茂通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • C++实现顺序表的方法

    C++实现顺序表的方法

    本文给大家带来了C++实现顺序表的方法,代码简单易懂,附有注释,感兴趣的朋友一起看下吧
    2016-08-08
  • 使用Qt开发一个简易图片查看器的完整指南

    使用Qt开发一个简易图片查看器的完整指南

    本文介绍了使用Qt开发一个简易图片查看器的完整过程,项目通过3个核心控件(QLabel、QLineEdit、QPushButton)实现图片选择、路径显示和图片预览功能,感兴趣的小伙伴可以了解下
    2026-05-05
  • c++智能指针的超详细讲解

    c++智能指针的超详细讲解

    c++程序设计中经常会用堆内存,程序员要自己管理内存的申请和释放,使用原始指针,容易造成堆内存泄漏(忘记释放),二次释放,使用智能指针能更好的管理堆内存,下面这篇文章主要给大家介绍了关于c++智能指针的相关资料,需要的朋友可以参考下
    2022-06-06
  • 浅谈C语言Free空指针会怎样

    浅谈C语言Free空指针会怎样

    在C语言中,使用free函数释放一个空指针是安全的,不会引发任何错误或异常,本文就来详细的介绍一下,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • C语言详细分析讲解关键字const与volatile的用法

    C语言详细分析讲解关键字const与volatile的用法

    在C语言中,我们经常会见到const和volatile这两个关键字,那么我们今天就来介绍下这两个关键字,提起 const 关键字,我们可能首先想到的是经过它修饰的变量便是常量了。其实我们这种想法是错误的,其实 const 修饰的变量是只读的,其本质还是变量
    2022-04-04
  • C++中的几种排序算法

    C++中的几种排序算法

    这篇文章主要介绍了C++中的几种排序算法,需要的朋友可以参考下
    2014-02-02
  • C++ boost::asio编程-域名解析详细介绍

    C++ boost::asio编程-域名解析详细介绍

    这篇文章主要介绍了C++ boost::asio编程-域名解析详细介绍的相关资料,这里附有实例代码,帮助大家学习理解这部分知识,需要的朋友可以参考下
    2016-11-11

最新评论