当前位置: 首页 > news >正文

函数指针与指针函数

一、引言

在C语言中,函数指针指针函数是两个容易混淆但本质完全不同的概念。它们的语法相似,但用途和实现机制截然不同。本文将通过定义解析、代码示例、应用场景对比总结,帮助你彻底理解这两者的区别与核心用法。


二、函数指针详解

1.什么是函数指针?

函数指针指向函数的指针变量。它存储的是函数的入口地址,通过该指针可以间接调用函数。

语法声明
返回值类型 (*指针变量名)(参数列表);
  • 示例int (*funcPtr)(int, int);
    funcPtr 是一个指向函数的指针,该函数接受两个 int 参数并返回 int 类型。
赋值与调用
// 定义一个普通函数
int add(int a, int b) {return a + b;
}int main() {int (*funcPtr)(int, int) = add;  // 将函数地址赋给指针int result = funcPtr(3, 4);      // 通过指针调用函数printf("Result: %d\n", result);  // 输出 7return 0;
}

2.内存图解:

#include <stdio.h>// 定义函数原型
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }int main() {// 声明函数指针:返回int, 参数两个intint (*operation)(int, int); operation = &add; // 指向add函数printf("10 + 5 = %d\n", operation(10, 5)); // 输出: 15operation = sub;  // &可省略,函数名即地址printf("10 - 5 = %d\n", operation(10, 5)); // 输出: 5return 0;
}

代码区内存布局:
+----------------------+
|  add函数机器指令     | 地址: 0x4000
+----------------------+
|  sub函数机器指令     | 地址: 0x5000
+----------------------+栈内存:
+----------------------+
| main::operation      |
| [指针变量]           |
| 当前值: 0x4000       | → 指向add函数
+----------------------+

3.函数指针的应用场景

⑴.回调函数(Callback Functions)

回调函数是通过函数指针传递给其他函数的函数,常用于事件驱动编程。

#include <stdio.h>// 回调函数类型
typedef int (*Callback)(int, int);// 计算器函数,接受回调函数作为参数
int calculate(int a, int b, Callback operation) {return operation(a, b);
}int main() {int result;// 使用加法函数作为回调result = calculate(5, 3, add);printf("5 + 3 = %d\n", result);  // 输出: 8// 使用减法函数作为回调result = calculate(5, 3, subtract);printf("5 - 3 = %d\n", result);  // 输出: 2return 0;
}

⑵.函数表(Function Table)

函数表是存储函数指针的数组,常用于实现状态机或命令解析器。

#include <stdio.h>// 定义函数指针类型
typedef void (*CommandHandler)();// 命令处理函数
void help() { printf("显示帮助信息\n"); }
void quit() { printf("退出程序\n"); }
void list() { printf("列出所有文件\n"); }int main() {// 函数表CommandHandler commands[] = {help, quit, list};// 根据用户输入调用对应函数int choice;printf("请选择命令(0-帮助, 1-退出, 2-列表): ");scanf("%d", &choice);if (choice >= 0 && choice < 3) {commands[choice]();  // 调用对应函数} else {printf("无效命令\n");}return 0;
}

⑶.动态函数选择

根据运行时条件调用不同函数:

int subtract(int a, int b) {return a - b;
}int main() {int choice = 1;int (*funcPtr)(int, int) = (choice == 1) ? add : subtract;printf("Result: %d\n", funcPtr(10, 5));  // 输出 5(若 choice=1)return 0;
}

4. 函数指针与 typedef

使用typedef可以简化函数指针的定义:

typedef int (*MathOperation)(int, int);// 使用typedef定义的类型创建函数指针
MathOperation op = add;

三、指针函数(Pointer Function)

1. 基本概念与语法

指针函数是返回指针的函数,即函数的返回值类型是指针。常用于动态内存分配、返回数组或结构体等场景。

定义语法

返回指针类型 函数名(参数列表);
  • 示例int* getArray();
    getArray 是一个函数,返回一个指向 int 的指针。

示例代码

// 动态分配数组并返回指针
int* createArray(int size) {int* arr = (int*)malloc(size * sizeof(int));for (int i = 0; i < size; i++) {arr[i] = i * 10;}return arr;
}int main() {int* arr = createArray(5);  // 调用指针函数for (int i = 0; i < 5; i++) {printf("%d ", arr[i]);  // 输出 0 10 20 30 40}free(arr);  // 释放内存return 0;
}

2.内存图解:

#include <stdio.h>
#include <stdlib.h>// 指针函数:返回int指针的函数
int* createIntArray(int size) {int* arr = (int*)malloc(size * sizeof(int));for (int i = 0; i < size; i++) {arr[i] = i * 10;}return arr; // 返回动态数组首地址
}int main() {int* myArr = createIntArray(5);printf("arr[2] = %d\n", myArr[2]); // 输出: 20free(myArr); // 必须释放内存!return 0;
}

内存图解:

      栈内存                         堆内存
+------------------+        +---------------------+
|  main::myArr     | -----> | createIntArray分配区 |
| [指针变量]       |        +---------------------+
+------------------+        | 地址: 0x1000        || [0]: 0    [1]: 10   || [2]: 20  [3]: 30   | ← 返回的指针指向这里| [4]: 40            |+---------------------+

3. 指针函数的应用场景

⑴. 动态内存分配

指针函数常用于封装内存分配逻辑:

// 返回动态分配的字符串
char* create_string(const char* initial_value) {char* str = (char*)malloc(strlen(initial_value) + 1);if (str != NULL) {strcpy(str, initial_value);}return str;
}

⑵.返回静态数组或结构体

指针函数可以返回静态存储的数组或结构体:

// 返回静态数组的指针
int* get_static_array() {static int arr[5] = {10, 20, 30, 40, 50};return arr;
}

⑶.链表节点创建

返回链表节点的指针:

struct Node* createNode(int value) {struct Node* node = (struct Node*)malloc(sizeof(struct Node));node->data = value;node->next = NULL;return node;
}

4.注意事项

  • 避免返回局部变量的指针:局部变量在函数返回后会被销毁,导致指针悬空。
// 错误示例:返回局部变量的指针
int* wrong_function() {int num = 100;return &num;  // 危险!num在函数返回后已销毁
}

四、函数指针 vs 指针函数:核心区别

对比项函数指针指针函数
本质指针变量,存储函数地址函数,返回值是指针
语法声明int (*funcPtr)(int, int);int* func(int, int);
用途间接调用函数、回调函数、策略模式返回动态分配的内存、链表节点、数组等
示例funcPtr = add; result = funcPtr(3,4);arr = createArray(5);
记忆技巧
  • 函数指针指针指向函数(遥控器控制家电)。
  • 指针函数函数返回指针(工厂生产指针)。

五、实战案例:函数指针实现排序策略

需求

实现一个通用排序函数,支持升序和降序排序。

代码实现

#include <stdio.h>// 比较函数指针类型
typedef int (*CompareFunc)(int a, int b);// 升序比较
int ascending(int a, int b) {return a - b;
}// 降序比较
int descending(int a, int b) {return b - a;
}// 通用排序函数
void sort(int* arr, int size, CompareFunc compare) {for (int i = 0; i < size - 1; i++) {for (int j = 0; j < size - i - 1; j++) {if (compare(arr[j], arr[j + 1]) > 0) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}int main() {int arr[] = {5, 2, 9, 1, 3};int size = sizeof(arr) / sizeof(arr[0]);// 升序排序sort(arr, size, ascending);printf("Ascending: ");for (int i = 0; i < size; i++) printf("%d ", arr[i]);  // 1 2 3 5 9// 降序排序sort(arr, size, descending);printf("\nDescending: ");for (int i = 0; i < size; i++) printf("%d ", arr[i]);  // 9 5 3 2 1return 0;
}

六、注意事项与常见错误

  1. 函数指针的参数匹配
    函数指针的返回值类型和参数列表必须与目标函数一致,否则可能导致未定义行为。

  2. 指针函数的内存管理
    若指针函数返回动态分配的内存(如 malloc),需在使用后手动 free,避免内存泄漏。

  3. 野指针风险
    未初始化或已释放的函数指针可能导致程序崩溃,建议初始化为 NULL 并检查空值。


七、总结

  • 函数指针操作函数的工具,适用于回调、动态调度等场景。
  • 指针函数返回指针的函数,常用于动态内存分配和数据结构操作。
  • 理解两者的本质区别和语法差异,是编写高效、灵活C代码的关键。

记住

  • 函数指针是“指针 → 函数”,指针函数是“函数 → 指针”。
  • 通过实际项目中的灵活应用(如事件驱动、链表操作),你将逐步掌握它们的强大之处!

http://www.lqws.cn/news/554347.html

相关文章:

  • 如何提取mdd字典中音频文件并转化为mp3
  • 基于社区电商场景的Redis缓存架构实战02-社区电商项目实战
  • 嵌入式单片机中SPI串行外设接口控制与详解
  • cannot import name ‘TextKwargs‘ from ‘transformers.processing_utils‘
  • git使用详解和示例
  • 蓝凌流程引擎流程图格式化实现原理全解
  • 湖北理元理律师事务所:债务优化中的法律理性与人文温度
  • Blender速成班-知识补充
  • 13-StringBuilder类的使用
  • 如何利用企业内部数据评测大模型的实际表现?
  • SpringBoot3.x整合Knife4j接口文档
  • STM32HAL 旋转编码器教程
  • ASProxy64.dll导致jetbrains家的IDE都无法打开。
  • navigation2学习笔记
  • 前后端分离实战2----前端
  • Push-T, AloHa, Rlbench三个仿真环境信息
  • c# sugersql 获取子表数据排序
  • 大一C语言期末选择题和填空题题库
  • 求职招聘小程序源码招聘小程序搭建招聘小程序定制开发
  • Kioptrix Level1
  • 第十节:Vben Admin 最新 v5.0 (vben5) 快速入门 - 菜单管理(下)
  • 从台式电脑硬件架构看前后端分离开发模式
  • 数字孪生技术引领UI前端设计新革命:实时交互与模拟预测
  • 【Elasticsearch】全文检索 组合检索
  • 基于多径信道的分集接收技术性能优化与仿真分析
  • 单端反激变换器MATLAB仿真设计方案
  • 开源AI大模型驱动下的“信息找人“范式变革:AI智能名片与S2B2C商城小程序源码的技术重构
  • vue3中实现高德地图地址搜索自动提示(附源码)
  • WHERE 子句中使用子查询:深度解析与最佳实践
  • 【论文阅读笔记】知网SCI——基于主成分分析的空间外差干涉数据校正研究