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

C/C++ 指针与函数

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. 重要注意事项

🚫 避免的陷阱

  1. 不要返回局部变量的地址
  2. 不要返回局部数组的指针
  3. 动态分配的内存必须记得释放

✅ 最佳实践

  1. 优先使用返回值而不是返回指针
  2. 使用引用参数来修改外部变量
  3. 必要时使用智能指针管理动态内存
  4. 函数指针使用typedef提高可读性

编译警告

使用 -Wall 选项编译可以检测悬挂指针问题:

g++ -Wall -o program main.cpp

总结

技术优点缺点适用场景
返回值指针灵活易产生悬挂指针一般不推荐
动态内存控制生命周期需手动管理内存需要长期存在的数据
静态变量简单安全全局状态,线程不安全单线程简单场景
参数传递最安全需要预先定义变量推荐使用
函数指针实现回调语法复杂策略模式、回调机制

推荐优先使用参数传递和直接返回值的方式,避免不必要的指针操作。

http://www.dtcms.com/a/349860.html

相关文章:

  • Tesseract OCR之页面布局分析
  • 朴素贝叶斯:用 “概率思维” 解决分类问题的经典算法
  • ​Visual Studio + UE5 进行游戏开发的常见故障问题解决
  • 【区间DP】P1063 [NOIP 2006 提高组] 能量项链
  • 基于深度学习的人声分离系统设计与实现
  • Apache Commons Math_Java科学计算的利器
  • AP服务发现中两条重启检测路径
  • 南京魔数团:AR技术引领远程协作新纪元
  • C++ Core Guidelines 核心理念
  • ios webgl音频问题
  • 深入解析:为什么应该避免使用 atoi、atol 和 atof 函数
  • 集成算法概述与分类
  • 大数据毕业设计选题推荐-基于大数据的超市销售数据统计分析系统-Hadoop-Spark-数据可视化-BigData
  • 【opengl 实践】 windows下vscode配置遇到的问题
  • week4-[二维数组]幻方检测
  • 【Android】Activity和Fragment之间的通讯
  • 大型电动化工程机械设备智能施工试验场的网络设计方案
  • java基础(十五)计算机网络
  • 【栈 - LeetCode】739.每日温度
  • 深入理解JVM垃圾收集器:垃圾收集器
  • Vue3 + Golang Gin 实现客服实时聊天系统(WebSocket + Socket.IO 详解)
  • Maven、Spring Boot、Spring Cloud以及它们的相互关系
  • iptables 防火墙技术详解
  • 如何通过虚函数实现多态?
  • 文入门Ubuntu:从零到精通的Linux之旅
  • 数学建模-整数规划(IP)
  • FunASR语音识别框架流式识别模型切换
  • SpringBoot的条件装配原理
  • SpringBoot3集成Oauth2.1——10重启程序Token失效(RSA持久化)
  • Java项目-苍穹外卖_Day1