C++数组指针与函数指针
在系统编程和底层开发中,数组指针与函数指针是C++的必备技能。本文将聚焦实用场景,让你快速掌握核心用法。
一、数组指针:遍历与多维数组处理
1.1 基本用法
int arr[5] = {1,2,3,4,5};int* ptr = arr; // 数组退化为指针
cout << *(ptr + 2); // 输出3(指针运算)// 遍历数组
for(int i = 0; i < 5; ++i) {cout << *ptr++ << " "; // 1 2 3 4 5
}
1.2 多维数组处理(游戏/图像领域常用)
// 动态创建2D数组
int** matrix = new int*[3];
for(int i=0; i<3; ++i)matrix[i] = new int[4]{0};// 指针方式访问
*(*(matrix + 1) + 2) = 42; // matrix[1][2] = 42// 现代替代方案:更推荐使用vector
vector<vector<int>> safeMatrix(3, vector<int>(4));
二、函数指针:回调机制与策略模式
2.1 声明与使用
// 函数原型
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }// 函数指针类型
using MathFunc = int (*)(int, int);// 使用函数指针
MathFunc op = add;
cout << op(3,2); // 5op = subtract;
cout << op(3,2); // 1
2.2 实际应用:回调函数(嵌入式/GUI开发)
// 按钮点击回调
using ClickHandler = void (*)(void);void registerClick(ClickHandler handler) {// 模拟点击事件handler();
}void onButtonClick() {cout << "Button clicked!";
}int main() {registerClick(onButtonClick);
}
三、函数指针数组:状态机与命令模式
// 状态处理函数
enum State { IDLE, RUNNING, ERROR };void idleHandler() { /* 空闲处理 */ }
void runningHandler() { /* 运行处理 */ }
void errorHandler() { /* 错误处理 */ }// 函数指针数组
using StateHandler = void(*)();
StateHandler handlers[] = {idleHandler,runningHandler,errorHandler
};// 状态机驱动
void processState(State s) {handlers[s](); // 调用对应状态函数
}
四、现代C++替代方案(更安全)
4.1 std::function
+ Lambda(优先选择)
#include <functional>// 可存储函数对象、Lambda等
std::function<void()> callback;// 设置Lambda回调
callback = [] { cout << "Modern callback";
};// 触发回调
callback();
4.2 函数指针数组升级版
// 类型安全的处理容器
std::vector<std::function<void()>> actions;// 添加处理函数
actions.push_back([] { /* 任务1 */ });
actions.push_back([] { /* 任务2 */ });// 执行所有任务
for (auto& action : actions) {action();
}
五、内存管理关键技巧
// 动态数组指针
int* dynArr = new int[10];// 必须配套delete[]
delete[] dynArr; // 现代替代:智能指针
auto safeArr = std::make_unique<int[]>(10);
// 自动释放,无内存泄漏风险
六、函数签名匹配技巧
当函数签名不一致时:
// 原始函数
void log(int level, const char* msg) { /*...*/ }// 需要适配的函数指针类型
using SimpleLogger = void(*)(const char*);// 适配方案
auto adapter = [](const char* msg) {log(1, msg); // 固定日志级别
};// 使用适配后的指针
SimpleLogger logger = adapter;
logger("Error occurred");
七、性能考量与取舍
方案 | 执行效率 | 安全性 | 灵活性 |
---|---|---|---|
原始指针 | ⚡️⚡️⚡️ | ★★☆ | ★★☆ |
std::function | ⚡️⚡️ | ★★★★★ | ★★★★★ |
Lambda | ⚡️⚡️ | ★★★★★ | ★★★★★ |
建议:性能关键路径用原始指针,其他场景用现代方案
八、实战案例:命令解析器
// 命令处理函数原型
using CommandHandler = void(*)(const std::string&);// 命令映射表
std::map<std::string, CommandHandler> commands = {{"start", [](auto&){ /* 启动逻辑 */ }},{"stop", [](auto&){ /* 停止逻辑 */ }},{"help", [](auto&){ /* 帮助信息 */ }}
};void executeCommand(const std::string& cmd) {if (commands.find(cmd) != commands.end()) {commands[cmd](""); // 执行命令} else {cout << "Unknown command";}
}
九、常见错误与规避
-
指针越界
int arr[3] = {1,2,3}; int* p = arr; p[3] = 4; // 未定义行为!
规避:用
std::array
代替原始数组 -
函数签名不匹配
void func(int); void (*wrongPtr)() = func; // 编译错误
规避:使用
auto
推导类型auto ptr = func; // 自动推导正确类型
-
忘记释放内存
int* p = new int; // 忘记delete导致内存泄漏
规避:立即用智能指针包裹
auto sp = std::make_unique<int>(42);
掌握指针的本质与正确用法,能让你在底层开发、性能优化等场景游刃有余。现代C++提供了更安全的替代方案,但在与C库交互、嵌入式开发等场景中,原始指针仍是必要技能。
推荐:C++学习一站式分享