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

C++ 函数指针与排序策略

文章目录

  • 一、指针函数
  • 二、函数指针
    • 2.1 定义
    • 2.2 函数指针变量的声明
    • 2.3 函数指针作为参数
    • 2.4 函数的指针类型
    • 2.5 函数指针类型作用
  • 三、指定排序规则
    • 3.1 说明
    • 3.2 策略模式 - 对扩展开放,对修改关闭
    • 3.3 通用排序算法示例
    • 3.4 使用模板实现通用排序
    • 3.5 排序算法补充

一、指针函数

本质:是一个函数,其返回值类型为指针(即函数执行后返回一个地址)。
先看下面的函数声明,注意,此函数有返回值,返回值为 int*,即返回值是指针类型的:

int *f(int a, int b);

上面的函数声明又可以写成如下形式:

int* f(int a, int b);

让指针标志 * 与 int 紧贴在一起,而与函数名 f 间隔开,这样看起来就明了些了:f 是函数名,返回值类型是一个 int 类型的指针。

特点

  • 是函数,不是指针
  • 返回值必须是一个合法的指针(避免返回局部变量的地址)

示例代码

#include <stdio.h>
#include <stdlib.h>int* arrayPrint(int* array, int size)
{int i;for(i = 0; i < size; i++){// *array++先读数据,然后++printf("array[%d] = %d; ", i, *array++);}putchar('\n');// 指针归位for(i = 0; i < size; i++){array--;}return array;
}int main()
{int array[3] = {10, 12, 13};arrayPrint(array, sizeof(array)/sizeof(array[0]));int* array2 = arrayPrint(&array[0], sizeof(array)/sizeof(array[0]));int i;for(i = 0; i < 3; i++){// *array++先读数据,然后++printf("array2[%d] = %d; ", i, *array2++);}putchar('\n');system("pause");return 0;
}

二、函数指针

2.1 定义

与数据项类似,函数也有地址,函数的地址是存储其机器语言代码内存的开始地址;函数指针指向的是函数而非对象。

如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,在这段存储空间的起始地址(又称入口地址)称为这个函数的指针。

  • 函数指针是指向函数的指针变量
  • 通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数
  • 函数指针可以像一般函数一样,用于调用函数、传递参数
  • 当我们把函数名作为一个值使用时,该函数自动地转换成指针。还可以直接使用指向函数的指针调用该函数

2.2 函数指针变量的声明

typedef int(*fun ptr)(int, int);

声明一个指向同样参数、返回值的函数指针类型。想要声明一个可以指向函数的指针,只需要用指针替换函数名即可。

示例

bool lengthCompare(const string& s1, const string& s2);  // 函数
bool (*pf)(const string&, const string&);               // 函数指针

pf 是一个指向函数的指针,其中该函数的参数是两个 const string 的引用,返回值是布尔类型。

注意*pf 两端的括号必不可少,如果省略括号,就变成了一个返回值为 bool 指针的函数,而不是指向函数的指针。

示例代码

#include <stdio.h>
#include <stdlib.h>// 无参数无返回值函数
void printWelcome()
{printf("欢迎来到,矩阵造物!\n");
}// 有参数有返回值函数
int add(int a, int b)
{return a + b;
}int main()
{// 定义函数指针。函数指针是专用的,格式要求很严格void (*p)();// 函数名就是地址,和数组一样p = printWelcome;// 通过指针来调用函数p();       // 直接通过指针名字+()(*p)();    // 取内容// 返回类型(*指针名称)(参数列表);int (*fp1)(int, int);void (*fp2)();// 获取函数的地址fp1 = add;fp2 = printWelcome;printf("Result = %d\n", fp1(10, 9));fp2();return 0;
}

2.3 函数指针作为参数

函数指针可以作为参数传递给其他函数,这在实现回调函数等场景中非常有用。

示例

#include <iostream>
#include <string>
using namespace std;bool lengthCompare(const string& s1, const string& s2);
void display(const string& s1, const string& s2, bool(*p)(const string&, const string&));int main()
{string name1 = "Sandy";string name2 = "Jane and Sandy";// 定义一个函数指针bool(*pf)(const string&, const string&);// 给函数指针赋值。指针指向lengthCompare函数pf = lengthCompare;// 使用函数指针作为参数display(name1, name2, pf);return 0;
}

2.4 函数的指针类型

函数指针有严格的类型要求,不同类型的函数指针不能随意互换使用。

#include <stdio.h>
#include <stdlib.h>int sum(int number1, int number2)
{int sum = number1 + number2;printf("sum = %d \n", sum);return sum;
}void myPrint()
{printf("Hello World \n");
}int main()
{int (*p1)(int a, int b);int (*p2)(int, int);int (*p3)();void (*p4)();p1 = sum;p2 = sum;p3 = sum;p4 = sum;  // 这里会有警告,但可能能编译通过printf("p1 = %d \n", p1(10, 10));printf("p2 = %d \n", p2(100, 100));printf("p3 = %d \n", p3(50, 100));// printf("p4 = %d \n", p4(12, 34)); // 返回值类型报错p4(200, 200);  // 可能能运行但结果未定义// 正确使用p4 = myPrint;p4();  // 正确调用return 0;
}

2.5 函数指针类型作用

此时你可能认为函数指针类型没实际作用,但其实函数指针类型就是一个规范,其中从前面的返回值类型也可以看出来,不规定参数,你可以随意传参,甚至可以不传,但是如果规定了参数,你就必须传参。

函数指针类型的主要作用是:

  1. 类型安全:确保函数指针只能指向具有相同签名的函数,避免错误的函数调用
  2. 代码规范:明确函数指针所指向函数的参数和返回值类型,提高代码可读性和可维护性
  3. 回调机制:实现回调函数、策略模式等高级编程技巧
  4. 动态绑定:在运行时决定调用哪个函数,实现多态性

注意事项

  • 函数指针类型规定了参数和返回值的类型,使用时必须严格遵守
  • 不匹配的函数指针赋值可能导致未定义行为
  • 使用 typedef 可以简化复杂函数指针类型的声明,提高代码可读性
// 使用typedef简化函数指针类型声明
typedef int (*MathOperation)(int, int);// 现在可以这样声明函数指针变量
MathOperation addPtr = add;
MathOperation subtractPtr = subtract;

三、指定排序规则

3.1 说明

在C++中,函数可以作为另一个函数的参数,这种机制通常通过函数指针来实现。函数指针是指向函数的指针变量,它存储着函数的内存地址,允许我们将函数作为参数传递给其他函数。

不是常量指针不能用 sizeof 去接收,不能在冒泡排序的函数中使用 sizeof 去接收待排序数组的大小

3.2 策略模式 - 对扩展开放,对修改关闭

策略模式是一种设计模式,它允许在运行时选择算法的行为。通过使用函数指针,我们可以将不同的算法(函数)传递给同一个函数,从而实现在不修改原有代码的情况下扩展功能。

#include <iostream>
using namespace std;// 定义几个示例函数
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 calculate(int a, int b, int (*operation)(int, int)) {return operation(a, b); // 调用传递进来的函数
}int main() {int x = 10, y = 5;// 将不同的函数作为参数传递给calculate函数cout << "加法: " << calculate(x, y, add) << endl;cout << "减法: " << calculate(x, y, subtract) << endl;cout << "乘法: " << calculate(x, y, multiply) << endl;return 0;
}

3.3 通用排序算法示例

我们可以使用函数指针来实现通用的排序算法,允许调用者指定排序规则。

#include <iostream>
using namespace std;struct Dog {int age;int price;Dog() {}Dog(int age, int price) : age(age), price(price) {}
};// 比较函数,根据年龄降序排序
bool compareByAge(Dog a, Dog b) {return a.age > b.age;
}// 比较函数,根据价格降序排序
bool compareByPrice(Dog a, Dog b) {return a.price > b.price;
}// 冒泡排序函数,接受一个函数指针作为比较规则
void BubblingSort(Dog* array, int length, bool (*COMPARE)(Dog a, Dog b)) {for (int i = 0; i < length - 1; i++) {for (int j = 0; j < length - 1 - i; j++) {if (COMPARE(array[j], array[j+1])) {Dog temp = array[j];array[j] = array[j+1];array[j+1] = temp;}}}
}int main() {Dog dogs[5];dogs[0] = Dog(12, 877);dogs[1] = Dog(2, 233);dogs[2] = Dog(8, 456);dogs[3] = Dog(2, 1335);dogs[4] = Dog(4, 12435);// 根据年龄排序BubblingSort(dogs, 5, compareByAge);for (int i = 0; i < 5; i++) {cout << "狗: " << dogs[i].age << " " << dogs[i].price << endl;}// 根据价格排序BubblingSort(dogs, 5, compareByPrice);for (int i = 0; i < 5; i++) {cout << "狗: " << dogs[i].age << " " << dogs[i].price << endl;}return 0;
}

3.4 使用模板实现通用排序

#include <iostream>
using namespace std;// 比较函数模板
template <typename T>
bool compare(T a, T b) {return a > b; // 默认降序
}// 冒泡排序模板
template <typename T>
void BubblingSort(T* array, int length, bool (*COMPARE)(T a, T b)) {for (int i = 0; i < length - 1; i++) {for (int j = 0; j < length - 1 - i; j++) {if (COMPARE(array[j], array[j+1])) {T temp = array[j];array[j] = array[j+1];array[j+1] = temp;}}}
}// 针对Dog结构的比较函数
struct Dog {int age;int price;Dog() {}Dog(int age, int price) : age(age), price(price) {}
};bool compareDogByAge(Dog a, Dog b) {return a.age > b.age;
}int main() {// 对整型数组排序int intArray[] = {12, 23, 45, 78, 53, 98, 450, 7};BubblingSort(intArray, 8, compare<int>);for (int i = 0; i < 8; i++) {cout << intArray[i] << " ";}cout << endl;// 对Dog数组排序Dog dogs[5];dogs[0] = Dog(12, 877);dogs[1] = Dog(2, 233);dogs[2] = Dog(8, 456);dogs[3] = Dog(2, 1335);dogs[4] = Dog(4, 12435);BubblingSort(dogs, 5, compareDogByAge);for (int i = 0; i < 5; i++) {cout << "狗: " << dogs[i].age << " " << dogs[i].price << endl;}return 0;
}

这里 T 是一个占位符,调用时会被具体类型替换。

  • BubblingSort<int> 会生成针对 int 的版本。
  • BubblingSort<Dog> 会生成针对 Dog 的版本。

注意事项

  • 函数指针的类型必须与所指向函数的类型完全匹配,包括返回类型和参数类型。
  • 在传递函数指针时,可以直接使用函数名,因为函数名会自动转换为函数指针
  • 使用函数指针可以实现回调函数,这在事件驱动编程和异步编程中非常常见。

3.5 排序算法补充

#include <stdio.h>
#include <stdlib.h>#define true 1
#define false 0
typedef unsigned char bool;// 定义排序函数类型
typedef void (*SORTTYPE)(int* array, int length, bool (*COMPARE)(int a, int b));// 函数声明
void Sort(int* array, int length, SORTTYPE sortType, bool (*COMPARE)(int a, int b));
void BubblingSort(int* array, int length, bool (*COMPARE)(int a, int b));
void InsertSort(int* array, int length, bool (*COMPARE)(int a, int b));
bool compare(int a, int b);// 比较函数
bool compare(int a, int b) {return a < b ? true : false;
}int main() {// 数据int array[] = {12, 23, 45, 78, 53, 98, 450, 7};int length = sizeof(array) / sizeof(int);// 使用冒泡排序printf("冒泡排序结果: ");Sort(array, length, BubblingSort, compare);for (int i = 0; i < length; i++) {printf("%d ", array[i]);}putchar('\n');// 重置数组int array2[] = {12, 23, 45, 78, 53, 98, 450, 7};// 使用插入排序printf("插入排序结果: ");Sort(array2, length, InsertSort, compare);for (int i = 0; i < length; i++) {printf("%d ", array2[i]);}putchar('\n');return 0;
}// 排序回调函数
void Sort(int* array, int length, SORTTYPE sortType, bool (*COMPARE)(int a, int b)) {sortType(array, length, COMPARE);
}// 冒泡排序实现
void BubblingSort(int* array, int length, bool (*COMPARE)(int a, int b)) {printf("使用冒泡排序: ");for (int i = 0; i < length - 1; i++) {for (int j = 0; j < length - 1 - i; j++) {if (COMPARE(array[j], array[j + 1])) {int temp = array[j];array[j] = array[j + 1];array[j + 1] = temp;}}}
}// 插入排序实现
void InsertSort(int* array, int length, bool (*COMPARE)(int a, int b)) {printf("使用插入排序: ");for (int i = 1; i < length; i++) {int key = array[i];int j = i - 1;while (j >= 0 && COMPARE(array[j], key)) {array[j + 1] = array[j];j--;}array[j + 1] = key;}
}

在 C/C++ 中,当我们把一个数组作为函数参数传递时,数组类型会自动退化为指针类型。在函数内部,arr 只是一个指针变量,它只保存了数组首元素的地址,并不知道有多少个元素。因为函数内部只知道“地址”,不知道“元素个数”,所以必须额外传入长度参数。

例如,在冒泡排序函数中,我们传递了数组的长度length,而不是在函数内部使用sizeof(array)/sizeof(array[0]),因为array实际上是一个指针,而不是数组。

// 错误示例:在函数内部使用sizeof获取数组长度
void BubblingSort(int* array, bool (*COMPARE)(int a, int b)) {int length = sizeof(array) / sizeof(array[0]); // 错误:array是指针,sizeof(array)是指针的大小,而不是数组的大小// ...
}// 正确示例:传递数组长度
void BubblingSort(int* array, int length, bool (*COMPARE)(int a, int b)) {// ...
}
http://www.dtcms.com/a/391249.html

相关文章:

  • 12分钟讲解Python核心理念
  • 01数据结构-串和KMP算法
  • 前端性能优化实用方案(三):骨架屏提升30%用户感知速度
  • NVR设备ONVIF接入平台EasyCVR视频融合平台智慧小区视频监控一站式建设方案
  • window XP环境下配置VC6.0的Win32汇编语言开发环境
  • 【算法】0_算法工程师常见算法题
  • 免费插件分享 | BaseTool
  • sk04.【scikit-learn基础】--『监督学习』之 线性回归
  • Ubuntu终端切换WiFi
  • eBest渠道商管理软件:快消品渠道数字化的“破局利器”
  • 基于protues的电子时钟仿真与模拟
  • FastProperty 高效的属性读写设置
  • 【开题答辩全过程】以 基于Java的失物招领平台为例,包含答辩的问题和答案
  • 【7/20】前后端整合:Vue.js 调用 Express API,操作 MongoDB 数据,实现用户管理系统
  • 【8/20】用户认证基础:JWT 在 Express 中的实现,实现安全登录
  • 独立站有哪些建站工具
  • Linux 终端常用快捷键整理
  • 跨域的两种解决方法
  • 小程序中获取年月日时分的组件
  • Redis热升级秘籍:零停机迁移方案与工具链
  • 时序数据库选型指南深度解析IoTDB架构设计与性能对比
  • springboot超市管理系统的设计与实现(代码+数据库+LW)
  • 让Trae写一个AI的api中继服务
  • 跨国制造业SD-WAN:延迟下降78%,运维成本下降53%
  • MySQL服务启动不成功的可能解决方法
  • 硬解码出现画面回退分析
  • P1068 [NOIP 2009 普及组] 分数线划定-普及-
  • 用python语言如何排大小
  • pycharm连接GitHub,怎么配置 SSH 密钥并改用 SSH 连接
  • ​​[硬件电路-265]:电源系统要考虑的因素包括:不同的输出电压、隔离防干扰、防反、防浪涌、电压可调、电源开关、电池、可充电、低纹波、低噪声、防波动等