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

C++:参数传递方法(Parameter Passing Methods)

目录

 1. 值传递(Pass by Value)

2. 地址传递(Pass by Address) 

 3. 引用传递(Pass by Reference)

 数组作为函数参数(Array as Parameter)

数组作为函数返回值


什么是函数(Function)?

定义:函数是一段封装了特定功能的代码块(Code Block),接受输入(参数,Parameters),执行操作,并可选返回结果。函数提高代码的模块化(Modularity)和可复用性(Reusability)。

为什么需要函数?

  • 核心需求:程序需要重复执行某些逻辑(如计算、数据处理),而不希望重复写代码。函数将逻辑封装,调用时只需提供输入。

什么是结构体(Structure)?

定义:结构体是一种用户定义的数据类型(User-Defined Data Type),将多个相关变量(成员,Members)组织成一个整体,方便管理和操作数据。

为什么需要结构体?

  • 核心需求:程序需要处理一组相关数据(如学生的姓名、学号、成绩),单独定义变量会很零散,结构体将它们组合成一个逻辑单元。

 1. 值传递(Pass by Value)

void swap(int a, int b) { // 值传递,a和b是x和y的副本int temp = a;a = b;b = temp;
}
int main() {int x = 10, y = 20;swap(x, y); // 传递x和y的副本std::cout << "x: " << x << ", y: " << y << std::endl; // 输出:x: 10, y: 20return 0;
}

原理:

  • 函数接收到的是ab 的拷贝副本。

  • 这些副本在函数的栈区 stack里存在。

  • 修改这些副本不会影响原始变量。

 

工作原理:a和b是x和y的副本,函数修改a和b,但x和y不变。

优点:

  • 安全:函数无法修改原始数据,适合不需要改变输入的场景。

  • 简单:代码直观,适合小数据(如int)。

缺点:

  • 无法实现swap目标:原始变量x和y未交换。

  • 效率低:对于大对象(如结构体、数组),复制副本耗时耗空间。

适用场景:只读操作或小数据传递。 

2. 地址传递(Pass by Address) 

指针传递将变量的内存地址(Memory Address)传递给函数,函数通过指针(Pointer)操作原始数据。 

void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}

原理:

  • 传入的是变量的地址(内存位置)。

  • 函数通过指针 *a*b 解引用,直接修改了内存中的值。

  • 实际修改的是原始变量。

 

工作原理:a和b存储x和y的地址,通过*(解引用,Dereference)访问和修改原始数据。 

  • 优点:

    • 可修改原始数据:成功实现swap目标,x和y值交换。

    • 高效:只传递地址(通常4或8字节),适合大对象(如结构体、数组)。

    • 支持空指针检查:可用nullptr表示无效数据。

缺点:

  • 复杂性增加:需要使用*和&,容易出错(如忘记解引用)。

  • 需检查空指针:否则可能导致崩溃(未定义行为,Undefined Behavior)

 3. 引用传递(Pass by Reference)

引用传递将变量的**引用(Reference)**传递给函数,函数直接操作原始数据。引用是C++特有的机制,像是变量的“别名”(Alias)。

void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}

原理:

  • & 并不是取地址,而是声明a 和 b 是引用(Reference)。

  • 它们是原始变量的别名。

  • 编译器在底层偷偷用指针处理,但你写的代码不需要 *&

 

 工作原理:a和b是x和y的引用,操作a和b直接修改x和y。

优点:

  • 可修改原始数据:成功实现swap目标。

  • 语法简洁:无需*或&,代码像值传递一样直观。

  • 高效:传递引用(底层是地址),不复制数据。

缺点:

  • 可能意外修改:调用者可能不希望数据被改变,需明确意图。

  • 无空值检查:引用必须绑定有效变量,无法像指针用nullptr。

 数组作为函数参数(Array as Parameter)

void printArray(int arr[], int size) {for (int i = 0; i < size; i++)cout << arr[i] << " ";
}

在 C++ 中,数组作为函数参数传递时,实际上传递的是数组的首地址(指针)! 

🔬 C++ 中数组作为参数时,会退化为指针

void printArray(int arr[], int size);
// 实际等价于:
void printArray(int* arr, int size);

原因:

在函数参数中,数组类型会退化(decay)为指向其首元素的指针。这是 C/C++ 语言设计的一部分,背后原因:

  • 函数参数不能接收整个数组的“值”,因为数组不能整体赋值(不能复制整个内存块)。

  • 所以只能传递一个地址,也就是数组第一个元素的地址 &arr[0]

  • 这也是为什么你必须单独传一个 size 参数 —— 因为函数内无法知道数组长度。

数组作为函数返回值

C++中,函数不能直接返回局部数组(栈上分配,函数结束即销毁),需要通过指针(堆内存或外部数组)或现代C++容器(如std::vector)实现。 

int[] getArray() {  // ❌ 错误:不能返回数组类型int arr[5] = {1, 2, 3, 4, 5};return arr;     // ❌ 错误:返回局部数组
}
  • 它是一个在栈区(Stack)上分配的内存块。

  • 函数执行完毕后,这块内存就会被自动销毁。

  • 返回这个地址 → 悬空指针(Dangling Pointer) → 引发未定义行为。

✅ 正确的做法:用“能长期存在”的内存来返回数组

我们有几种安全的替代方案,分别基于不同内存管理方式:

 方法 1:返回堆上数组

int* getArray() {int* arr = new int[5]{1, 2, 3, 4, 5};  // 分配在堆上return arr;  // 返回地址
}

特点:

  • 返回的是堆内存地址,函数执行完也不会释放。

  • 必须手动 delete[] 来释放内存,否则内存泄漏。

 

方法 2:用 static 关键字返回静态数组 

int* getArray() {static int arr[5] = {1, 2, 3, 4, 5};return arr;  // 返回的是静态变量地址
}

特点:

  • static 数组会在程序整个生命周期中都存在。

  • 不在栈上,不会被销毁。

  • 不需要 delete,但多次调用会共享同一个数组。

http://www.lryc.cn/news/2397605.html

相关文章:

  • 大语言模型的推理能力
  • 基于BERT和GPT2的实现来理解Transformer的结构和原理
  • .net consul服务注册与发现
  • WifiEspNow库函数详解
  • rsync使用守护进程启动服务
  • React 核心概念与生态系统
  • 使用React Native开发新闻资讯类鸿蒙应用的准备工作
  • node-sass 报错
  • Redis的安装与使用
  • Linux服务器运维10个基础命令
  • 2024年数维杯国际大学生数学建模挑战赛C题时间信号脉冲定时噪声抑制与大气时延抑制模型解题全过程论文及程序
  • C# 控制台程序获取用户输入数据验证 不合规返回重新提示输入
  • 【大模型面试每日一题】Day 31:LoRA微调方法中低秩矩阵的秩r如何选取?
  • 使用source ~/.bashrc修改环境变量之后,关闭服务器,在重启,环境变量还有吗?
  • SQL 窗口函数深度解析:ROW_NUMBER 实战指南
  • React从基础入门到高级实战:React 生态与工具 - React 国际化(i18n)
  • leetcode93.复原IP地址:回溯算法中段控制与前导零处理的深度解析
  • TDengine 运维——巡检工具(安装前检查)
  • MySQL主从复制深度解析:原理、架构与实战部署指南
  • [SC]SystemC dont_initialize的应用场景详解(二)
  • 【Linux】权限chmod命令+Linux终端常用快捷键
  • Java八股文智能体——Agent提示词(Prompt)
  • Go语言的context
  • 快速掌握 GO 之 RabbitMQ 结合 gin+gorm 案例
  • JVM——SubstrateVM:AOT编译框架
  • 【HarmonyOS 5】鸿蒙Taro跨端框架
  • 数据库原理 试卷
  • 【Qt开发】对话框
  • Ubuntu上进行VS Code的配置
  • 阴盘奇门 api数据接口