前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[c语言日寄]指针进阶:函数指针数组——转换表

[c语言日寄]指针进阶:函数指针数组——转换表

作者头像
siy2333
发布于 2025-02-20 01:12:51
发布于 2025-02-20 01:12:51
12200
代码可运行
举报
文章被收录于专栏:来自csdn的博客来自csdn的博客
运行总次数:0
代码可运行

前言

在C语言的编程世界中,函数指针是一种非常强大且灵活的工具,它允许我们将函数像变量一样操作。而函数指针数组则进一步扩展了这种能力,可以将多个函数组织在一起,形成一个“转换表”,从而实现高效的函数调度和模块化设计。今天,我们就通过一个具体的案例来深入探讨函数指针数组的使用,以及它在C语言中的重要性和应用场景。

一、题目引入

在编程中,我们经常会遇到需要根据不同的输入条件调用不同函数的情况。例如,实现一个简单的计算器,根据用户输入的运算符选择相应的加、减、乘、除运算。传统的做法是使用if-else或switch-case语句来判断并调用对应的函数。然而,这种方法在面对大量分支时,代码会变得冗长且难以维护。

现在,假设我们需要实现一个支持多种运算的计算器,如果使用switch-case语句实现,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return a / b; }


int main() {
    char op;
    int a, b;
    printf("Enter operator and two operands: ");
    scanf(" %c%d%d", &op, &a, &b);

    switch (op) {
        case '+':
            printf("Result: %d\n", add(a, b));
            break;
        case '-':
            printf("Result: %d\n", subtract(a, b));
            break;
        case '*':
            printf("Result: %d\n", multiply(a, b));
            break;
        case '/':
            printf("Result: %d\n", divide(a, b));
            break;
        default:
            printf("Invalid operator!\n");
    }
    return 0;
}

可以看到,switch-case语句中包含了大量重复的模式,代码显得冗长且难以扩展。如果新增一个运算符,我们需要修改switch-case语句,增加新的case分支。那么,有没有一种更优雅的方法来实现这种功能呢?

答案是肯定的——使用函数指针数组!

二、知识点分析

1. 函数指针的基本概念

在C语言中,函数指针是一种特殊的指针类型,它可以指向一个函数的入口地址。通过函数指针,我们可以间接调用函数,就像调用普通变量一样。函数指针的定义方式如下:

返回值类型 (*指针变量名)(参数类型列表); 例如,定义一个指向int类型函数的指针,该函数接收两个int参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int (*func_ptr)(int, int);

函数指针的使用方式如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int add(int a, int b) { return a + b; }

int main() {
    int (*func_ptr)(int, int);  // 定义函数指针
    func_ptr = add;             // 将函数指针指向add函数
    int result = func_ptr(3, 4); // 通过函数指针调用add函数
    printf("Result: %d\n", result); // 输出结果
    return 0;
}

2. 函数指针数组的定义与初始化

函数指针数组是一个包含多个函数指针的数组。通过函数指针数组,我们可以将多个函数组织在一起,形成一个“转换表”。函数指针数组的定义方式如下:

返回值类型 (*数组名[数组大小])(参数类型列表); 例如,定义一个包含5个函数指针的数组,每个函数都接收两个int参数并返回int类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int (*func_array[5])(int, int);

接下来,我们可以将不同的函数赋值给数组中的每个元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }

int main() {
    int (*func_array[5])(int, int); // 定义函数指针数组
    func_array[0] = add;           // 将add函数赋值给数组的第一个元素
    func_array[1] = subtract;      // 将subtract函数赋值给数组的第二个元素
    func_array[2] = multiply;      // 将multiply函数赋值给数组的第三个元素
    func_array[3] = divide;        // 将divide函数赋值给数组的第四个元素
    // 调用函数指针数组中的函数
    int result = func_array[2](3, 4); // 调用multiply函数
    printf("Result: %d\n", result);   // 输出结果
    return 0;
}

3. 函数指针数组的使用

通过函数指针数组,我们可以根据输入的索引直接调用对应的函数,而无需使用冗长的条件判断语句。例如,我们可以将运算符映射到函数指针数组的索引上,从而实现高效的函数调度。 假设我们有以下函数定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return a / b; }
int mod(int a, int b) { return a % b; }

我们可以将这些函数存储在函数指针数组中,并根据输入的运算符索引对应的函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return a / b; }
int mod(int a, int b) { return a % b; }

int main() {
    int (*func_array[6])(int, int) = {add, subtract, multiply, divide, mod, power};
    char op;
    int a, b;

    printf("Enter operator and two operands: ");
    scanf(" %c%d%d", &op, &a, &b);

    int index;
    switch (op) {
        case '+': index = 0; break;
        case '-': index = 1; break;
        case '*': index = 2; break;
        case '/': index = 3; break;
        case '%': index = 4; break;
        default:
            printf("Invalid operator!\n");
            return 1;
    }

    int result = func_array[index](a, b);
    printf("Result: %d\n", result);
    return 0;
}

在这个例子中,我们通过switch-case语句将运算符映射到函数指针数组的索引上,然后直接通过索引调用对应的函数。这种方法大大减少了冗长的条件判断语句,使代码更加简洁和易于维护。

三、注意事项

1. 函数指针的类型匹配

在使用函数指针数组时,必须确保所有函数的签名(返回值类型和参数列表)完全一致。否则,编译器可能会报错或导致运行时错误。例如,如果函数指针数组的定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int (*func_array[5])(int, int);

那么,所有存储在func_array中的函数都必须返回int类型,并且接收两个int参数。如果某个函数的签名不匹配,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void print_result(int a, int b) { printf("%d\n", a + b); }

则不能将其赋值给func_array,因为它的返回值类型是void,而不是int。

2. 空指针检查

在调用函数指针时,必须确保指针不为空。如果函数指针未初始化或被赋值为NULL,直接调用会导致未定义行为(如程序崩溃)。因此,在调用函数指针之前,建议进行空指针检查:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (func_array[index] != NULL) {
    int result = func_array[index](a, b);
    printf("Result: %d\n", result);
} else {
    printf("Function pointer is NULL!\n");
}

3. 索引越界检查

在使用函数指针数组时,必须确保索引在合法范围内。如果索引超出数组的边界,可能会导致访问非法内存,从而引发程序崩溃或其他不可预测的行为。因此,在使用索引之前,建议进行越界检查:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (index >= 0 && index < 6) {
    int result = func_array[index](a, b);
    printf("Result: %d\n", result);
} else {
    printf("Invalid index!\n");
}

4. 函数指针的动态赋值

在某些情况下,我们可能需要根据运行时条件动态地将函数指针赋值给函数指针数组。例如,根据用户输入选择不同的算法实现。在这种情况下,必须确保动态赋值的函数指针与数组的类型一致,并且在赋值后进行空指针检查。

四、拓展应用:状态机实现

函数指针数组在实现状态机时非常有用。状态机是一种常见的编程模式,用于根据不同的状态和输入条件执行不同的操作。通过将每个状态的处理函数存储在函数指针数组中,我们可以根据当前状态直接调用对应的处理函数,从而实现高效的状态切换。 假设我们有一个简单的状态机,用于处理用户输入的命令。状态机有以下状态:

  • IDLE:空闲状态,等待用户输入。
  • RUNNING:运行状态,执行用户输入的命令。
  • ERROR:错误状态,处理错误情况。

我们可以定义一个函数指针数组来存储每个状态的处理函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

void idle_state() {
    printf("Idle state: Waiting for command.\n");
}

void running_state() {
    printf("Running state: Executing command.\n");
}

void error_state() {
    printf("Error state: Handling error.\n");
}

int main() {
    void (*state_machine[3])() = {idle_state, running_state, error_state};
    int current_state = 0; // 初始状态为IDLE

    while (1) {
        printf("Enter command (0: IDLE, 1: RUNNING, 2: ERROR, -1: EXIT): ");
        scanf("%d", &current_state);

        if (current_state == -1) {
            break;
        } else if (current_state >= 0 && current_state < 3) {
            state_machine[current_state](); // 调用当前状态的处理函数
        } else {
            printf("Invalid command!\n");
        }
    }
    return 0;
}

在这个例子中,我们通过函数指针数组state_machine存储每个状态的处理函数,并根据用户输入的命令调用对应的函数。这种方法大大简化了状态机的实现,使代码更加清晰和易于维护。

总结

函数指针数组是C语言中一个非常强大的工具,它允许我们将多个函数组织在一起,形成一个“转换表”。通过函数指针数组,我们可以实现高效的函数调度、状态机等功能。在使用函数指针数组时,需要注意函数指针的类型匹配、空指针检查、索引越界检查等问题,以确保代码的正确性和安全性。

如果你喜欢这篇文章,别忘了点赞和关注哦!我们下次再见! 关注窝,每三天至少更新一篇优质c语言题目详解~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-02-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
及时修复!苹果两大零日漏洞影响iPhone、iPad和Mac
近日,苹果公司发布紧急安全更新,此次更新修复了两个在攻击中被利用并影响 iPhone、iPad 和 Mac 设备的零日漏洞。据统计,自今年年初以来已修复的零日漏洞数量已达到 20 个。
FB客服
2023/12/03
5290
及时修复!苹果两大零日漏洞影响iPhone、iPad和Mac
苹果曝严重安全漏洞,喜提热搜第一
据媒体报道,苹果公司在周三(8月17日)发布了两份安全报告,承认公司的智能手机iPhone、平板电脑iPad和iMac电脑等产品存在严重的安全漏洞。 公开信息查询显示,该漏洞报告时间为 2022年6月9日,漏洞编号分别是CVE-2022-32894和CVE-2022-32893,主要影响以下两部分: 内核:应用程序或许能够以内核权限执行任意代码。 Webkit:处理恶意制作的网页内容可能会导致任意代码执行。 这些漏洞一旦被利用,黑客可直接获得设备的管理权限。苹果也指出,该漏洞很大可能已经被利用,强烈督
FB客服
2023/03/30
4170
苹果曝严重安全漏洞,喜提热搜第一
赶快更新!Apple 出现多个安全漏洞
The Hacker News 网站披露,苹果公司近日推出了 iOS、iPadOS、macOS 的安全更新,以解决一个 0day 漏洞(追踪为 CVE-2023-23529)。 研究表明,CVE-2023-23529 漏洞与 WebKit 开源浏览器引擎中的类型混淆错误有关,一旦攻击者成功利用,便可在目标系统上执行任意代码。 WebKit 是一个主要用于 Safari,Dashboard,Mail 和其它一些 Mac OS X 程序的开源浏览器引擎,在手机上的应用十分广泛(例如 Android、iPhon
FB客服
2023/02/24
5590
赶快更新!Apple 出现多个安全漏洞
Apple 修复了新的“零日”漏洞
Security Affairs 资讯网站披露,苹果公司已经成功修复一个新的 WebKit 零日漏洞,(追踪为CVE-2022-22620)。据悉,该漏洞可能已在野外被积极利用,会对iOS、iPadOS、macOS 和 Safari 产生恶劣影响。
FB客服
2022/02/25
4740
Apple 修复了新的“零日”漏洞
苹果发布iOS 15.0.2和iPadOS 15.0.2,紧急修复0day漏洞
2021年10月12日凌晨1点,距离上个版本发布仅10天,苹果就向全球用户推送了 iOS15.0.2系统,同时发布的还有 iPadOS15.0.2。本次更新除了修复信息与照片、应用等一系列问题外,紧急修复了一个正在被黑客广泛利用的0day漏洞,漏洞编号CVE-2021-30883。
FB客服
2021/10/21
4970
苹果设备发现新漏洞,可以恶意访问用户数据
苹果公司修订了它上个月发布的安全公告,更新了影响iOS、iPadOS和macOS的三个新漏洞。 第一个漏洞是Crash Reporter组件中的一个竞赛条件(CVE-2023-23520),可使恶意攻击者以root身份读取任意文件。iPhone制造商表示,它通过额外的验证来解决这个问题。 另外两个漏洞,归功于Trellix研究员Austin Emmitt,位于Foundation框架中(CVE-2023-23530和CVE-2023-23531),可以武器化来实现代码执行。 苹果公司表示:“应用程序可能能够
FB客服
2023/02/27
5350
苹果设备发现新漏洞,可以恶意访问用户数据
一个iPhone的WiFi零点击漏洞,再曝远程入侵威胁
7月19日,最新研究发现,Wi-Fi网络名称漏洞可完全禁用iPhone网络功能,且可实施远程代码执行,但今年早些时候苹果公司已经悄悄修复。
FB客服
2021/07/27
7110
一个iPhone的WiFi零点击漏洞,再曝远程入侵威胁
苹果发布紧急更新,今年第十个零日漏洞
苹果于7月10日发布了新一轮快速安全响应 (RSR) 更新,以解决在攻击中利用的一个新零日漏洞。
FB客服
2023/08/08
3070
苹果发布紧急更新,今年第十个零日漏洞
苹果更新系统没有引入新功能,官方却强烈建议立即更新
苹果上周五推出了iOS 14.4.2,iPadOS 14.4.2和watchOS 7.3.3,和以往更新不同,这次更新并没有引入任何新功能,但苹果公司却建议所有用户立即安装,原因竟是旧系统中出现了较为严重的安全漏洞。
用户7454708
2023/05/09
2800
苹果更新系统没有引入新功能,官方却强烈建议立即更新
iPhone史上最复杂的攻击链,卡巴斯基曝光苹果处理器“神秘后门”
近日,卡巴斯基安全研究人员Boris Larin披露了iPhone历史上最复杂的间谍软件攻击——三角测量(Triangulation)的技术细节。
FB客服
2024/01/04
5230
iPhone史上最复杂的攻击链,卡巴斯基曝光苹果处理器“神秘后门”
苹果iOS曝doorLock漏洞,能让手机“变砖”
据BleepingComputer网站报道,在苹果Apple HomeKit 中发现了一个名为“doorLock”的新型持续拒绝服务漏洞,影响的系统版本从IOS14.7到IOS15.2。
FB客服
2022/01/05
5890
苹果iOS曝doorLock漏洞,能让手机“变砖”
任正非发声:把活下来作为最主要纲领;安卓山寨 iOS 启动器下载超 5000 万次;公司停电,程序员去网吧写代码 | EA周报
6、安卓山寨 iOS 启动器下载超 5000 万次,过去三年一直在安卓上重现 iOS 体验
yuanyi928
2022/09/27
7190
任正非发声:把活下来作为最主要纲领;安卓山寨 iOS 启动器下载超 5000 万次;公司停电,程序员去网吧写代码 | EA周报
苹果发布紧急补丁以修复被积极利用的零日漏洞
近日,苹果发布了一个紧急安全补丁,以解决两项被积极利用以入侵iPhone、iPad和Mac的零日漏洞。
FB客服
2022/04/12
3310
苹果发布紧急补丁以修复被积极利用的零日漏洞
苹果WWDC24即将来袭!iOS 18新功能大揭秘!
随着时间进入六月,科技界的目光再次聚焦在苹果年度盛会——苹果WWDC24!苹果公司即将在这场盛会上发布一系列令人期待的新技术和软件更新,让我们一同来了解即将到来的重磅内容!
猫头虎
2024/05/24
1520
苹果WWDC24即将来袭!iOS 18新功能大揭秘!
GitLab爆出安全漏洞,允许黑客接管账户
GitLab :一个基于网络的 Git 存储库,主要面向需要远程管理代码的开发团队,目前共拥有约 3000 万注册用户和 100 万付费客户。
FB客服
2024/05/28
1.4K0
GitLab爆出安全漏洞,允许黑客接管账户
黑客不讲武德,苹果好自为之
上周,在第三场秋季新品发布会上,作为开启 Apple silicon 时代的新操作系统,苹果正式推出了 macOS Big Sur。在功能上,Big Sur 明显“借鉴”了苹果自家 iOS 和 iPadOS 的特征,比如引入控制中心,包含 WiFi、蓝牙、屏幕亮度、声音等调节选项等等,可见 Big Sur 是苹果打通三大系统的一个重要手段。
深度学习与Python
2020/12/07
1.9K0
iMessage是怎么成为“黑灰产的乐园”
对于这些垃圾短信,最好的办法就是别点开直接删除,上当/被骗的第一步就是从点开这些短信开始。
FB客服
2024/04/15
2130
iMessage是怎么成为“黑灰产的乐园”
苹果曝严重漏洞,可窃听用户与Siri对话
据The Hacker News 10月27日消息,在苹果近期披露的漏洞中包含了名为SiriSpy的 iOS 和 macOS系统漏洞,使具有蓝牙访问权限的应用程序能够窃听用户与 Siri 的对话。
FB客服
2022/11/14
4000
苹果曝严重漏洞,可窃听用户与Siri对话
立刻更新你的苹果设备!苹果被曝2大安全漏洞,无需交互就能被植入间谍软件
就在这两天,一家安全组织发现了苹果设备的2个最新漏洞,平板、手机、电脑等都受影响——
量子位
2023/09/19
2980
立刻更新你的苹果设备!苹果被曝2大安全漏洞,无需交互就能被植入间谍软件
SolarWinds 曝出五个严重的 RCE 漏洞
SolarWinds 近期修补了 Access Rights Manager (ARM) 解决方案中的五个远程代码执行 (RCE) 漏洞,其中包括三个允许未经验证利用的严重安全漏洞!
FB客服
2024/02/26
3020
SolarWinds 曝出五个严重的 RCE 漏洞
推荐阅读
相关推荐
及时修复!苹果两大零日漏洞影响iPhone、iPad和Mac
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 前言
  • 一、题目引入
  • 二、知识点分析
    • 1. 函数指针的基本概念
  • 2. 函数指针数组的定义与初始化
    • 3. 函数指针数组的使用
  • 三、注意事项
    • 1. 函数指针的类型匹配
    • 2. 空指针检查
    • 3. 索引越界检查
    • 4. 函数指针的动态赋值
  • 四、拓展应用:状态机实现
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档