C++: 函数参数传递

最后更新:2026-08-26

第10课我们学了函数的基础,知道函数可以接收参数。

但参数到底是怎么传给函数的?函数里改了参数,外面的变量会变吗?

这就是这一课要讲的——参数传递方式


1. 传值(Pass by Value)

(1) 1.1 基本用法

传值是 C++ 的默认参数传递方式——实参的值会复制一份给形参。

CPP
#include <iostream>

void modifyValue(int x) { // x 是形参(副本)
 x = 100; // 修改的是副本,不影响原变量
 std::cout << "函数里的 x = " << x << std::endl;
}

int main() {
 int a = 5;
 modifyValue(a); // 传值:a 的值复制给 x
 std::cout << "main 里的 a = " << a << std::endl; // a 还是 5
 return 0;
}

💡 重点: 传值时,函数里修改形参,不会影响实参。

(2) 1.2 传值的优缺点

优点 缺点
安全(函数不能修改实参) 大对象复制开销大(如大数组、大结构体)
思路清晰 无法让函数"返回"多个值


2. 传地址(Pass by Pointer)

如果你想让函数修改外部的变量,可以传地址(指针)。

(1) 2.1 基本用法

CPP
#include <iostream>

void modifyValue(int* x) { // x 是指针
 *x = 100; // 解引用,修改指针指向的值
 std::cout << "函数里的 *x = " << *x << std::endl;
}

int main() {
 int a = 5;
 modifyValue(&a); // 传地址:把 a 的地址传给函数
 std::cout << "main 里的 a = " << a << std::endl; // a 变成了 100
 return 0;
}

💡 重点: 传地址时,函数通过指针可以修改实参的值。

(2) 2.2 为什么能修改?

步骤 说明
1 int a = 5; — 在内存中开辟一块空间,存 5
2 modifyValue(&a); — 把 a 的地址传给函数
3 int* x 接收地址,指向 a 的内存空间
4 *x = 100; — 通过指针修改 a 的值


3. 传引用(Pass by Reference)

C++ 引入了引用(reference),它是变量的"别名",比指针更安全、更易用。

(1) 3.1 基本用法

CPP
#include <iostream>

void modifyValue(int& x) { // x 是引用(别名)
 x = 100; // 修改 x 就是修改原变量
 std::cout << "函数里的 x = " << x << std::endl;
}

int main() {
 int a = 5;
 modifyValue(a); // 传引用:不用写 &,看起来像传值
 std::cout << "main 里的 a = " << a << std::endl; // a 变成了 100
 return 0;
}

💡 重点: 传引用时,形参是实参的别名,修改形参就是修改实参。

(2) 3.2 引用 vs 指针

对比 引用 指针
语法 int& x = a; int* x = &a;
是否能为空 ❌ 不能(必须初始化) ✅ 能(可以是 nullptr
是否要解引用 ❌ 不用(直接用) ✅ 要(用 *x
能否重新指向 ❌ 不能(一旦绑定,不能改) ✅ 能(可以指向别的变量)
推荐程度 ⭐⭐⭐⭐⭐(优先用) ⭐⭐⭐(必要时用)


4. 三种传递方式对比

▶ 示例 1:交换两个变量的值(难度⭐⭐)

方法一:传值(失败)

CPP
#include <iostream>

void swapFailed(int a, int b) { // ❌ 传值:修改的是副本
 int temp = a;
 a = b;
 b = temp;
}

int main() {
 int x = 3, y = 5;
 swapFailed(x, y);
 std::cout << "x = " << x << ", y = " << y << std::endl; // x=3, y=5(没交换)
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
x = 5, y = 3

方法二:传指针(成功)

CPP
#include <iostream>

void swapPointer(int* a, int* b) { // ✅ 传指针
 int temp = *a;
 *a = *b;
 *b = temp;
}

int main() {
 int x = 3, y = 5;
 swapPointer(&x, &y);
 std::cout << "x = " << x << ", y = " << y << std::endl; // x=5, y=3(交换了)
 return 0;
}

方法三:传引用(成功,推荐)

CPP
#include <iostream>

void swapReference(int& a, int& b) { // ✅ 传引用(推荐)
 int temp = a;
 a = b;
 b = temp;
}

int main() {
 int x = 3, y = 5;
 swapReference(x, y); // 看起来像传值,其实是传引用
 std::cout << "x = " << x << ", y = " << y << std::endl; // x=5, y=3(交换了)
 return 0;
}


5. 什么时候用哪种传递方式?

场景 推荐方式 原因
函数不需要修改参数 传值传 const 引用 安全、清晰
函数需要修改参数 传引用 语法简洁、安全
需要"返回"多个值 传引用 函数可以修改多个引用参数
参数是大对象(数组、结构体) 传 const 引用 避免复制开销
需要表示"没有"(如查找失败) 传指针 指针可以是 nullptr

💡 黄金法则: 优先用传引用,必要时用传指针,小对象可以用传值



6. const 引用

如果你不想让函数修改参数,但又想避免复制开销,可以用 const 引用

CPP
#include <iostream>
#include <string>

void printName(const std::string& name) { // const 引用:不能修改 name
 std::cout << "名字:" << name << std::endl;
 // name = "Alice"; // ❌ 错误:不能修改 const 引用
}

int main() {
 std::string myName = "MOTO";
 printName(myName); // 不用复制整个字符串,效率高
 return 0;
}

💡 重点: const 引用 是 C++ 中最常用的参数传递方式之一,兼顾了安全性和效率。



7. 数组作为参数

数组作为参数时,会退化成指针(后面会详细讲)。

CPP
#include <iostream>

// 数组作为参数,需要传数组长度
void printArray(int arr, int length) {
 for (int i = 0; i < length; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
}

int main() {
 int myArray[5] = {1, 2, 3, 4, 5};
 printArray(myArray, 5); // 传数组名(就是首元素地址)
 return 0;
}

💡 提示: 数组作为参数时,函数里不知道数组的长度,需要额外传一个长度参数。



8. 实战:多个返回值

▶ 示例 2:计算商和余数(难度⭐⭐)

CPP
#include <iostream>

// 用引用参数"返回"多个值
void divide(int a, int b, int& quotient, int& remainder) {
 quotient = a / b;
 remainder = a % b;
}

int main() {
 int a = 17, b = 5;
 int q, r;
 
 divide(a, b, q, r); // q 和 r 会被修改
 
 std::cout << a << " / " << b << " = " << q << " ... " << r << std::endl;
 // 输出:17 / 5 = 3 ... 2
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
17 / 5 = 3 ... 2

▶ 示例 3:默认参数使用(难度⭐)

CPP
#include <iostream>
#include <string>

// 带默认参数的函数
void greet(const std::string& name, const std::string& greeting = "你好") {
    std::cout << greeting << "," << name << "!" << std::endl;
}

int main() {
    greet("张三");              // 使用默认参数
    greet("李四", "早上好");     // 指定参数
    greet("王五", "晚上好");     // 指定参数
    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
你好,张三!
早上好,李四!
晚上好,王五!

预期输出:

TEXT 📖 仅展示
你好,张三!
早上好,李四!
晚上好,王五!

❓ 常见问题

Q:引用和指针到底有什么区别? A:> - 引用是变量的别名,指针是存储地址的变量 > - 引用必须初始化,指针可以是 nullptr > - 引用不能重新指向,指针可以 > - 优先用引用,除非需要表示"没有"(这时用指针) Q:为什么数组作为参数时,不需要写长度? A:因为数组会退化成指针。 > > void foo(int arr) { // 等价于 void foo(int* arr) > // arr 实际上是指针,不是数组 > } > Q:传值、传引用、传指针,哪个效率高? A:> - 小对象(如 int):传值最高(复制开销小) > - 大对象(如大数组、大结构体):传 const 引用最高(避免复制) > - 需要修改参数:传引用最高(语法简洁)


Q:关于function parameters最重要的是什么? A:先理解核心概念,再通过实践例子来巩固。

Q:如何高效练习function parameters? A:从简单例子开始,逐步增加难度,务必测试你的代码。

📖 小节


📝 作业

  1. 基础题 (Difficulty ⭐): 写一个函数 void addTen(int& x),给传入的变量加 10。在 main 里测试。

  2. 进阶题 (Difficulty ⭐⭐): 写一个函数 void minMax(int arr, int length, int& min, int& max),找出数组的最小值和最大值(用引用参数"返回")。

  3. 挑战题 (Difficulty ⭐⭐⭐): 写一个程序,实现"三个数排序":

  4. 写一个函数 void sortThree(int& a, int& b, int& c),把三个数按从小到大排序

  5. main 里让用户输入三个数,调用 sortThree,然后输出排序后的结果


9. 🚀 下一步

学会了参数传递,接下来我们学习 递归(第12课)—— 函数调用自己的神奇技巧!

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏