CC++ & Algorithm

C++值传递

中等20
语言版本:C++Python
概述:值传递就像复印一份资料给别人,你修改复印件不会影响原件。

值传递:把数字复印一份,原件不会变

小朋友,你有没有试过把自己的画复印一份送给同学?同学在复印件上画了小花,但你的原画一点也不会变。在C++里,值传递 就和这个例子一模一样。

当我们写一个函数时,如果参数是用普通变量写的(比如 int a),那么调用函数时,C++会把实参的值复制一份给形参。函数里操作的都是那个“复印件”,原件纹丝不动。

为什么要有值传递?

想象一下,你去小卖部买零食,你给了老板10块钱,老板会把这10块钱放进收银机里,然后找给你零钱。如果你之后又觉得零食不好吃,想退回去换,老板从收银机里拿钱还给你——但这里有个关键:你给的10块钱只是“复印件”吗?不,现实生活中钱是实物,拿走了就没有了。 但在C++中,如果函数要修改某个数值,而你不想让原来的数值被改掉,就可以用值传递。比如你想算一个数的平方,但不想改变这个数本身,值传递就非常合适。

核心概念:什么是“复印件”?

在C++函数调用时,如果参数是基本类型(如 int, double, char),函数的形参会得到实参的一份副本。函数内部对形参的任何修改,都只影响副本,不影响原来的实参。

生活中的例子:考试分数

假设你考试得了95分,老师让你把分数抄在班级记录本上。你在自己的草稿纸上不小心把95写成59,但班级记录本上的95分并不会变。这里,草稿纸上的分数就是“副本”,班级记录本上的分数是“原件”。

用代码看分数例子:

#include <iostream>
using namespace std;

// 函数:修改分数(但只是修改复印件)
void changeScore(int score) {   // score 是形参,是副本
    score = 59;                 // 修改副本为59
    cout << "在函数内部, 分数变成了: " << score << endl;
}

int main() {
    int myScore = 95;           // 原件 95 分
    cout << "调用前, 我的分数是: " << myScore << endl;
    changeScore(myScore);       // 把 myScore 的副本传给函数
    cout << "调用后, 我的分数仍然是: " << myScore << endl; // 还是95
    return 0;
}

运行结果:

调用前, 我的分数是: 95
在函数内部, 分数变成了: 59
调用后, 我的分数仍然是: 95

看到了吗?函数里把分数改成了59,但外面的 myScore 还是95分,因为函数只改了自己的“复印件”。

值传递的两个特点:安全但独立

  1. 安全:函数不能随意修改你的原始数据,保护了你的变量不被意外破坏。比如你有一个重要的游戏积分,你只想让函数计算一下奖励,不想让它乱改积分,就可以用值传递。

  2. 独立:函数内部和外部是两套数据,互不影响。就像你复印了一本作业给同桌,同桌在上面乱写乱画,你的原版作业还是干净的。

常见错误:以为函数能改变外部变量

新手最容易犯的错误就是:写了一个交换函数,以为能交换两个变量的值,结果发现外面的变量没变。

// 错误示范:企图用值传递交换两个数
void swap(int a, int b) {  // a和b都是副本
    int temp = a;
    a = b;
    b = temp;
}
// 在main里调用 swap(x, y); 后,x和y不会交换!

很多同学会疑惑:“我明明在函数里交换了a和b,为什么外面x和y没变?” 原因就是:a和b是x和y的复印件,你交换的是复印件,原件没动。 要真想交换,需要用引用传递或指针传递(后面会学)。

完整示例:计算圆面积但不修改半径

下面是一个更贴近生活的例子:计算圆的面积,但保证半径这个变量不会被函数内部改变。

#include <iostream>
using namespace std;

const double PI = 3.14159;   // 圆周率常量

// 值传递:计算圆的面积(不会修改半径)
double calcArea(double r) {   // r 是半径的副本
    double area = PI * r * r; // 用副本计算面积
    // 如果这里不小心写 r = 0; 也不会影响外面的半径
    return area;              // 返回面积
}

int main() {
    double radius = 5.0;      // 半径原件是5.0
    double result = calcArea(radius); // 把副本传给函数
    
    cout << "半径是: " << radius << endl;   // 仍然是5.0
    cout << "圆的面积是: " << result << endl;
    return 0;
}

运行结果:

半径是: 5
圆的面积是: 78.5397

注意:即使你在 calcArea 函数内部把 r 改成 0,外面的 radius 也不会变。这就是值传递的“安全”特性。

什么情况下适合用值传递?

  • 当你只需要读取数据,不需要修改时(例如计算平方、判断奇偶)。
  • 当数据量很小的时候(比如一个整数、一个字符),复制一份很便宜,不影响性能。
  • 当你不希望函数意外改变你的原始变量时(保护数据安全)。

如果数据很大(比如一个数组或长字符串),复制会花费很多时间和内存,这时候就不适合用值传递了,应该用引用或指针(后续会学到)。

相关指引

学完了值传递,你可能会好奇:“那如果想在函数里真正地修改外面的变量,该怎么做呢?” 别急,C++提供了另外两种参数传递方式:

  • 引用传递(Reference):给变量起个外号,函数里直接操作原件。
  • 指针传递(Pointer):用变量的地址来访问原件。

这些知识点会在更高级的课程里学到。想继续探索?可以先看看引用传递,它就像把作业原稿借给同桌,同桌在上面直接改,你的原稿也会变。

例题精讲

1单选题

在C++中,关于值传递的说法,下列哪一项是正确的?

A形参的改变会影响到实参
B形参是实参的一个副本,互不影响
C值传递时实参和形参共享同一内存地址
D值传递只能用于基本数据类型
2判断题

在C++的值传递中,函数内部对形参进行自增操作,主调函数中对应的实参变量也会随之增加。

3填空题
以下函数试图交换两个整数的值,但不会改变实参。补全函数定义。

void swap(int a, int b) {
    int temp = a;
    a = b;
    ___ = temp;
}
4单选题

若通过函数修改实参的值,以下哪种参数传递方式可以实现?

A值传递
B地址传递(指针)
C引用传递
D地址传递(指针)和引用传递
5填空题
运行以下程序,输出结果为:_____

#include <iostream>
using namespace std;
void increment(int x) {
    x++;
}
int main() {
    int a = 5;
    increment(a);
    cout << a;
    return 0;
}