C/C++ 指针与函数
C/C++ 函数与指针
- 1. 返回值是指针的函数(易产生悬挂指针)
- ❌ 错误示例:返回局部变量的地址
- ✅ 正确解决方案
- 方案1:动态内存分配
- 方案2:静态变量(有限使用)
- 方案3:传递参数(推荐)
- 2. 指向函数的指针
- 基本用法
- 函数指针作为参数
- 函数指针数组
- 3. 完整测试程序
- 4. 重要注意事项
- 🚫 避免的陷阱
- ✅ 最佳实践
- 编译警告
- 总结
1. 返回值是指针的函数(易产生悬挂指针)
❌ 错误示例:返回局部变量的地址
#include <iostream>
using namespace std;// 危险!返回局部变量的地址
int* dangerous_func() {int a = 10; // 局部变量,函数结束即销毁cout << "函数内a的地址: " << &a << ", 值: " << a << endl;return &a; // 返回已被销毁的内存地址
}// 另一个函数,可能重用相同内存
int* another_dangerous_func() {int b = 20;cout << "函数内b的地址: " << &b << ", 值: " << b << endl;return &b;
}void demo_dangling_pointer() {cout << "=== 悬挂指针演示 ===" << endl;int* pa = dangerous_func();cout << "pa指向地址: " << pa << ", 值: " << *pa << endl; // 未定义行为!int* pb = another_dangerous_func();cout << "pb指向地址: " << pb << ", 值: " << *pb << endl; // 未定义行为!cout << "再次访问pa: " << *pa << endl; // 可能显示随机值cout << endl;
}
✅ 正确解决方案
方案1:动态内存分配
int* safe_func_dynamic() {int* p = new int(100); // 在堆上分配内存cout << "动态分配地址: " << p << ", 值: " << *p << endl;return p; // 安全返回
}void demo_dynamic_memory() {cout << "=== 动态内存方案 ===" << endl;int* p = safe_func_dynamic();cout << "获取的值: " << *p << endl;delete p; // 必须手动释放!cout << endl;
}
方案2:静态变量(有限使用)
int* safe_func_static() {static int value = 200; // 静态变量,生命周期与程序相同cout << "静态变量地址: " << &value << ", 值: " << value << endl;return &value;
}void demo_static_variable() {cout << "=== 静态变量方案 ===" << endl;int* p = safe_func_static();cout << "获取的值: " << *p << endl;cout << endl;
}
方案3:传递参数(推荐)
void safe_func_param(int& result) {result = 300; // 通过引用修改外部变量cout << "参数地址: " << &result << ", 设置值: " << result << endl;
}void demo_parameter_passing() {cout << "=== 参数传递方案 ===" << endl;int value;safe_func_param(value);cout << "最终值: " << value << endl;cout << endl;
}
2. 指向函数的指针
基本用法
#include <iostream>
using namespace std;// 普通函数
int add(int a, int b) {return a + b;
}int multiply(int a, int b) {return a * b;
}void demo_function_pointer() {cout << "=== 函数指针演示 ===" << endl;// 定义一个指向函数的指针,注意,这是一个指针!typedef int (*MathFunc)(int, int);/*()优先级大于 * 运算符int *MathFunc(int,int)-->这是一个函数声明:返回值是int*的函数,函数名为MathFunc,参数为两个intint (*MathFunc)(int,int)-->(*MathFunc)告诉大家,我是一个名为MathFunc的指针,是什么类型的指针呢?-->(*MathFunc)()后面有个括号,原来是指向函数的指针。那这个函数是有什么参数,以及返回值是多少呢?ps:(*parr)[] 后面有个中括号,指向数组的-->int (*MathFunc)(int,int)-->指针指向的函数的参数是两个int变量,返回值是int。*/// 声明函数指针变量MathFunc funcPtr = nullptr;// 指向add函数funcPtr = add;cout << "加法结果: " << funcPtr(5, 3) << endl;// 指向multiply函数funcPtr = multiply;cout << "乘法结果: " << funcPtr(5, 3) << endl;cout << endl;
}
函数指针作为参数
// 计算器函数,接收函数指针作为参数
void calculator(int a, int b, int (*operation)(int, int)) {int result = operation(a, b);cout << a << " 和 " << b << " 的运算结果: " << result << endl;
}void demo_callback() {cout << "=== 回调函数演示 ===" << endl;calculator(10, 5, add); // 传递add函数calculator(10, 5, multiply); // 传递multiply函数cout << endl;
}
函数指针数组
void demo_function_array() {cout << "=== 函数指针数组 ===" << endl;// 定义函数指针数组int (*operations[2])(int, int) = {add, multiply};for (int i = 0; i < 2; i++) {cout << "操作" << i+1 << "结果: " << operations[i](6, 4) << endl;}cout << endl;
}
3. 完整测试程序
int main() {// 演示悬挂指针问题demo_dangling_pointer();// 演示正确解决方案demo_dynamic_memory();demo_static_variable();demo_parameter_passing();// 演示函数指针demo_function_pointer();demo_callback();demo_function_array();return 0;
}
4. 重要注意事项
🚫 避免的陷阱
- 不要返回局部变量的地址
- 不要返回局部数组的指针
- 动态分配的内存必须记得释放
✅ 最佳实践
- 优先使用返回值而不是返回指针
- 使用引用参数来修改外部变量
- 必要时使用智能指针管理动态内存
- 函数指针使用typedef提高可读性
编译警告
使用 -Wall
选项编译可以检测悬挂指针问题:
g++ -Wall -o program main.cpp
总结
技术 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
返回值指针 | 灵活 | 易产生悬挂指针 | 一般不推荐 |
动态内存 | 控制生命周期 | 需手动管理内存 | 需要长期存在的数据 |
静态变量 | 简单安全 | 全局状态,线程不安全 | 单线程简单场景 |
参数传递 | 最安全 | 需要预先定义变量 | 推荐使用 |
函数指针 | 实现回调 | 语法复杂 | 策略模式、回调机制 |
推荐优先使用参数传递和直接返回值的方式,避免不必要的指针操作。