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

c++ 函数参数传递

C++ 中的值传递和地址传递

在 C++ 中,函数参数传递主要有两种方式:值传递地址传递(指针传递和引用传递都属于地址传递的变体)。

1. 值传递

特点

  • 函数接收的是实参的副本
  • 对形参的修改不会影响原始变量
  • 适用于小型数据(基本类型、小型结构体)
void increment(int x) {x++;  // 只修改局部副本
}int main() {int a = 5;increment(a);cout << a;  // 输出 5,原始值未改变return 0;
}

值传递优缺点

优点

  • 安全,原始数据不会被意外修改
  • 实现简单直观

缺点

  • 对于大型对象,复制开销大
  • 无法通过参数返回修改结果

2. 地址传递

2.1 指针传递

void increment(int* x) {(*x)++;  // 解引用并修改原始值
}int main() {int a = 5;increment(&a);  // 传递地址cout << a;      // 输出 6,原始值被修改return 0;
}

2.2 引用传递

void increment(int& x) {x++;  // 直接修改原始值
}int main() {int a = 5;increment(a);  // 看起来像值传递,实际是引用传递cout << a;     // 输出 6return 0;
}

地址传递的优缺点

优点

  • 避免大型对象的复制开销(减少内存拷贝,提升性能)
  • 可以在函数中修改实参的值
#include <iostream>
using namespace std;void func(int a, int b, int c, int* max, int* min)
{// 先假设a是最大值,b是最小值*max = a;*min = b;if (b > a) {*max = b;*min = a;}// 检查c是否比当前最大值大if (c > *max) {*max = c;}// 检查c是否比当前最小值小else if (c < *min) {*min = c;}
}int main()
{int a = 5;int b = 8;int c = 1;int max, min;  // 声明max和min变量func(a, b, c, &max, &min);  // 传递max和min的地址cout << "max = " << max << ", " << "min = " << min << endl;return 0;
}

缺点

  • 可能意外修改原始数据(指针传递)
  • 指针可能为 nullptr(需要检查)
  • 引用不能重新绑定(有时是优点)

3. 对比表格

特性值传递指针传递引用传递
传递内容值的副本内存地址别名(隐式指针)
语法func(int x)func(int* x)func(int& x)
调用方式func(a)func(&a)func(a)
修改原始值不能
空值检查不需要需要不需要
性能小型数据高效大型数据高效大型数据高效
安全性中(可能空指针)
可读性直观需要理解指针直观

4. 现代C++最佳实践

  • 优先使用const引用传递大型只读对象
void printBigObject(const BigObject& obj);
  • 使用智能指针代替裸指针进行资源管理
void process(std::shared_ptr<Resource> res);

5. 示例:三种方式实现swap函数

// 值传递(无法实现swap)
void swap_fail(int a, int b) {int temp = a;a = b;b = temp;
}// 指针传递
void swap_ptr(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 引用传递(推荐)
void swap_ref(int& a, int& b) {int temp = a;a = b;b = temp;
}int main() {int x = 1, y = 2;swap_fail(x, y);cout << x << " " << y;  // 1 2(未交换)swap_ptr(&x, &y);cout << x << " " << y;  // 2 1(已交换)swap_ref(x, y);cout << x << " " << y;  // 1 2(再次交换)return 0;
}

为什么函数内部不能直接修改指针本身

在 C++ 中,函数参数传递默认是值传递,包括指针参数。

1. 指针参数的本质

当你传递指针给函数时:

void func(int* ptr) {ptr = new int(10);  // 这只会修改局部副本
}int main() {int* p = nullptr;func(p);// p 仍然是 nullptr!
}

这是因为:

  • 函数接收到的是指针的副本(指针值的拷贝)
  • 修改这个副本(ptr = ...)不会影响原始指针
  • 这就像值传递一个 int 参数一样

2. 可以修改指针指向的内容

虽然不能直接修改指针本身,但可以修改指针指向的内容

void modifyContent(int* ptr) {*ptr = 10;  // 这会修改指针指向的内存
}int main() {int x = 5;int* p = &x;modifyContent(p);// x 现在是 10
}

3. 如何真正修改指针本身

如果需要修改指针本身(而不仅是指向的内容),你需要:

方法1:使用指针的指针(二级指针)

void modifyPointer(int** ptrPtr) {*ptrPtr = new int(20);  // 修改原始指针
}int main() {int* p = nullptr;modifyPointer(&p);// p 现在指向新分配的 intdelete p;  // 记得释放内存
}

方法2:使用指针的引用(更推荐)

void modifyPointer(int*& ptrRef) {ptrRef = new int(30);  // 直接修改原始指针
}int main() {int* p = nullptr;modifyPointer(p);// p 现在指向新分配的 intdelete p;
}

4. 原始代码问题分析

void func(..., int* max, int* min) {max = &a;  // 这只修改了局部副本min = &b;  // 这只修改了局部副本
}

这些赋值操作只修改了函数内部的指针副本,不会影响 main() 中的原始指针。

5. 解决方案对比

方法示例优点缺点
返回值int* func()简单只能返回一个值
二级指针func(int** max)可以修改多个指针语法复杂
指针引用func(int*& max)语法简洁需要C++引用支持
修改指向的内容func(int* max)最简单需要预先分配内存

6. 最佳实践建议

  1. 如果只需要修改指针指向的内容,使用一级指针
  2. 如果需要修改指针本身,优先使用指针引用 (int*&)
  3. 在C代码中或需要兼容C时,使用二级指针 (int**)
  4. 考虑使用智能指针 (std::unique_ptr&) 来避免内存管理问题
http://www.xdnf.cn/news/270847.html

相关文章:

  • 推理能力:五一模型大放送
  • 硬件零基础入门(尚硅谷)
  • JavaScript中的AES加密与解密:原理、代码与实战
  • Day04 新增套餐
  • 双指针算法详解(含力扣和蓝桥杯例题)
  • 王道考研数据结构课后题代码题(2026版)——排序部分
  • 第5章 Python 基本数据类型详解(int, float, bool, str)
  • 融智学16字方针无歧义表述并构建人机协同的非零和博弈模型
  • systemd-notify(linux服务状态通知消息)
  • 视频编解码学习一之相关学科
  • Java框架“若依RuoYi”前后端分离部署
  • 2025年最新嵌入式开发STM32单片机详细教程(更新中)
  • GTS-400 系列运动控制器板(十四)----软限位使用
  • 多元随机变量协方差矩阵
  • 62常用控件_QDial的使用
  • Learning vtkjs之PolyDataNormals
  • Spring MVC注解式控制器开发
  • 计算方法实验五 插值多项式的求法
  • java 洛谷题单【算法2-2】常见优化技巧
  • 纯Java实现STDIO通信的MCP Server与客户端验证
  • 【Java】2025 年 Java 学习路线:从入门到精通
  • 【进阶】C# 委托(Delegate)知识点总结归纳
  • Spring事务管理
  • [计算机网络]数据链路层
  • 1993年地级市民国铁路开通数据(地级市工具变量)
  • Servlet (一)
  • 大数据技术:从趋势到变革的全景探索
  • Servlet+tomcat
  • 链表的回文结构题解
  • Linux 的 epoll 与 Windows 的 IOCP 详解