函数指针的应用

一、函数指针实现多态

  • 多态就是同一个执行但是实际结果不一样
  • C语言虽然没有多态,但是可以用函数指针指向不同的函数来实现同一个调用执行不同的结果

1.1 测试代码

#include <stdio.h>

//定义一个pFunc类型,这个函数指针类型指向一种特定参数列表和返回值得函数
typedef int (*pFunc)(int, int);

int add(int a, int b);
int sub(int a, int b);

int multiply(int a, int b);
int divide(int a, int b);

int main(void)
{
    pFunc p1 = NULL;
    int a, b, result = 0;
    char c;
    printf("请输入两个整数:\n");
    scanf("%d%d", &a, &b);
    getchar();//清除缓存区的\n
    printf("请输入运算符: + | - | * | / \n");
    scanf("%c", &c);
    
    /*用函数指针指向不同的函数*/
    p1 = c == '+' ? add : (c == '-' ? sub : (c == '*' ? multiply : divide));
    
    result = p1(a, b);
    printf("%d %c %d = %d\n",a, c, b, result);
    return 0;
}

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

int sub(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;
}

1.2 测试结果

多态

  • 我们可以发现,通过同一个执行p1(int, int),其返回的结果是可以不同的,这也就实现了多态
  • 测试代码中加入getchar();是为了清除缓冲区的'\n'linux为了提升效率,默认将输入的内容放在缓存区等一行输入完了再一次性把一行全部输出出来,判断一行有没有完的依据就是'\n'

二、结构体内嵌函数指针实现模块化编程

2.1 完成架构设计

1.1所述的简单计算器测试代码,我们可以将其分为

  • 上层:架构层:framework.c——应用程序框架的实现
  • 下层:原理层:calculator.c——业务原理的具体实现
  • 头文件:calculator.h——实现架构层与原理层之间的信息传递

实际工作时calculator.c是直接完成工作的,但是其中的关键部分是调用framework.c中的函数来完成的

2.2 头文件calculator.h参考代码

头文件用来实现不同层次之间的交互,需要注意:

  • 普通变量不要在头文件中定义
  • 枚举或者结构体要定义在头文件中
#ifndef _CALCULATOR_H_
#define _CALCULATOR_H_

/*定义函数指针*/
typedef int (*pFunc)(int, int);

/*定义接口*/
struct calculator_t
{
    int a;
    int b;
    pFunc p_cal;
};

/*函数原型声明*/
int calculator(const struct calculator_t *p);
int add(int a, int b);
int sub(int a, int b);
int multiply(int a, int b);
int divide(int a, int b);

#endif

2.3 架构层:framework.c 参考代码

架构层只需实现业务逻辑,为原理层提供一个函数接口(不用干活)

#include "calculator.h"
//上层接口
int calculator(const struct calculator_t *p)
{
    return p -> p_cal(p->a, p->b);
};

2.4 原理层:calculator.c 参考代码

注重实际实现,需要使用架构层的接口与头文件,填充上层的空白

  • 定义结构体变量
  • 填充结构体变量
  • 调用接口函数,传入参数
#include "calculator.h"
#include <stdio.h>

int main(void)
{
    /*定义结构体变量*/
    struct calculator_t my_cal;

    pFunc p1;
    int a, b, result = 0;
    char c;
    printf("请输入两个整数:\n");
    scanf("%d%d", &a, &b);
    printf("请输入运算符: + | - | * | / \n");
    getchar();//清除缓存区的\n
    scanf("%c", &c);
    p1 = c == '+' ? add : (c == '-' ? sub : (c == '*' ? multiply : divide));

   /*填充结构体变量*/
    my_cal.a = a;
    my_cal.b = b;
    my_cal.p_cal = p1;  

   /*调用接口函数,传入参数*/
    result = calculator(&my_cal);

    printf("%d %c %d = %d\n",a, c, b, result);

    return 0;
}

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

int sub(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;
}

2.5 测试结果

涉及到多个.c文件的编译:
$ gcc framework.c calculator.c -o XXX.exe

模块化编程.png

<think>好的,用户想了解C或C++中函数指针的使用方法和示例。首先,我需要回忆一下函数指针的基本概念。根据引用[2]和[3],函数指针是指向函数的指针变量,可以用来调用函数。那用户可能需要知道如何声明、初始化和使用函数指针。接下来,我得整理一下结构。先从定义开始,说明函数指针的声明方式,比如如何根据函数原型来声明指针。例如,一个返回int,参数为两个int的函数,其指针类型是int(*)(int,int)。然后,给出赋值和调用的方法,比如直接指向函数名或者使用取地址符号,调用时可以用(*ptr)()或者直接ptr()。 然后,考虑应用场景,比如回调函数,这在排序或事件处理中很常见。引用[3]中的例子是Add函数,可以演示如何用函数指针调用。另外,引用[2]中的例子展示了指针函数和函数指针的区别,可能需要强调两者的不同,避免混淆。 还要注意示例代码的正确性,确保语法正确,比如在C++中使用using或typedef来简化声明。比如typedefint (*FuncPtr)(int, int)可以让代码更易读。此外,动态绑定和多态的例子,比如根据输入选择不同的操作函数,这能展示函数指针的灵活性。用户可能还关心常见错误,比如函数指针类型不匹配导致的错误,或者空指针调用的问题。但用户的问题主要是用法和示例,这部分可能需要放在注意事项里简要提及。最后,生成相关问题,帮助用户深入理解,比如函数指针指针函数的区别,回调函数的应用,C++中的改进方式如std::function等。这样用户可以有进一步学习的路径。 需要确保回答结构清晰,分点说明,每个部分有示例代码,并正确引用提供的资料,比如引用[2]和[3]中的代码片段。同时,检查LaTeX格式是否符合要求,比如行内公式用$...$,独立公式用$$...$$,不过这个问题可能不涉及数学公式,但代码块需要用正确标记。</think>在C/C++中,函数指针是实现动态行为调用的重要工具,以下从5个核心场景详解其用法: ### 一、基础定义与调用 函数指针的声明遵循函数原型规则: ```c int (*func_ptr)(int, int); // 声明指向函数的指针 ``` 赋值时可直接取函数地址: ```c int Add(int a, int b) { return a + b; } func_ptr = &Add; // 或 func_ptr = Add; ``` 调用方式具有等价性: ```c int result = (*func_ptr)(3,5); // 传统方式 int result = func_ptr(3,5); // C++简化写法 ``` ### 二、回调函数实战 在排序算法中应用(参考qsort原型): ```c void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); int compare_int(const void *a, const void *b) { return *(int*)a - *(int*)b; } int arr[] = {5,2,8,1}; qsort(arr, 4, sizeof(int), compare_int); // 通过函数指针注入比较逻辑[^2] ``` ### 三、结构体封装 创建可扩展的接口: ```c typedef struct { int (*open)(const char*); void (*close)(int); } DeviceDriver; int usb_open(const char *dev) { /*...*/ } void usb_close(int fd) { /*...*/ } DeviceDriver usb_driver = {usb_open, usb_close}; ``` ### 四、多态实现 运行时动态绑定: ```c++ void encrypt_AES(const char* data) { /*...*/ } void encrypt_RSA(const char* data) { /*...*/ } void process_data(const char* data, void (*encryptor)(const char*)) { encryptor(data); // 动态选择加密算法 } ``` ### 五、类型安全进阶(C++11) 使用`using`提升可读性: ```cpp using MathFunc = int(*)(int,int); // C++11类型别名 MathFunc func = std::max; ``` #### 注意事项 1. 匹配返回值和参数类型 2. 空指针检查:`if(func_ptr != nullptr)` 3. C++推荐使用`std::function`和lambda表达式 ```mermaid graph TD A[函数指针声明] --> B[赋值函数地址] B --> C[调用函数指针] C --> D[回调函数应用] D --> E[多态实现] E --> F[类型安全封装] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值