上一课标准答案:

  1. 不能。 因为 a 是 test() 里的局部变量,只能在 test() 的作用域里使用。
  2. 输出:
6
6

因为每次调用 test(),都会重新创建一个新的 a = 5,然后 a++ 变成 6。
3. 可以。 因为 a 定义在外层 main() 里,内层 if 可以访问外层变量。
4. b 定义在 if 的 {} 里面,离开这对花括号后,它的作用域就结束了,所以外面不能直接使用。


第 13 课:值传递 —— 为什么函数里改了,外面却没变?

这一课非常重要,因为它直接通向后面的:

引用 &
指针 *
函数参数
数组
对象
机器人状态修改

先看一个很奇怪的例子。

#include <iostream>

void change(int a)
{
    a = 100;
}

int main()
{
    int x = 5;

    change(x);

    std::cout << x << std::endl;

    return 0;
}

你可能会直觉地觉得:

change(x) 里面把 a 改成了 100,那 x 应该也变成 100。

但实际输出是:

5

为什么?


1. 关键:a 和 x 不是同一个变量

看调用:

change(x);

假设:

x = 5;

调用函数时,C++ 会把 x 的值:

5

复制一份,交给函数参数:

int a

所以可以想象成:

main 里面:

x
┌─────┐
│  5  │
└─────┘


调用 change(x)

        复制一个 5
              ↓

change 里面:

a
┌─────┐
│  5  │
└─────┘

注意:

x 和 a 是两个不同的盒子。

只是开始时里面都放着 5。


2. 函数里面改的是 a

执行:

a = 100;

于是变成:

main:

x
┌─────┐
│  5  │
└─────┘


change:

a
┌─────┐
│ 100 │
└─────┘

所以改的是:

a

不是:

x

函数结束以后,a 消失。

而 x 从头到尾还是:

5

3. 这就叫“值传递”

专业名字:

pass by value,值传递

意思是:

把变量里的“值”复制一份传进去。

不是把原变量本身交进去。


4. 再看一个更明显的例子

void addOne(int number)
{
    number++;
}

然后:

int main()
{
    int count = 10;

    addOne(count);

    std::cout << count << std::endl;
}

调用时:

count = 10

复制给:

number = 10

然后函数里:

number++;

变成:

number = 11

但是:

count

依然:

10

所以最后输出:

10

5. 用“复印件”理解最简单

你可以把值传递理解成:

你把文件复印一份给别人。

原文件:

x = 5

复印件:

a = 5

别人把复印件改成:

a = 100

你的原文件:

x = 5

不会自动变化。

这就是值传递最好的直觉。


6. 那为什么之前 calculateError 没问题?

之前我们写:

double calculateError(double target, double current)
{
    return target - current;
}

调用:

double result = calculateError(50.0, 20.0);

这里我们根本不需要修改外部变量。

函数只是:

拿到两个值
↓
计算
↓
返回结果

所以值传递非常合适。


7. 值传递什么时候特别常见?

例如:

double square(double x)
{
    return x * x;
}

调用:

double result = square(3.0);

我们只是想让函数计算:

3 × 3

并不希望外面的变量被改掉。

所以值传递非常安全。


8. 一个机器人例子

double limitAngle(double angle)
{
    if (angle > 90.0)
    {
        angle = 90.0;
    }

    return angle;
}

调用:

double joint_angle = 120.0;

double safe_angle = limitAngle(joint_angle);

函数收到:

angle = 120

然后改成:

angle = 90

返回:

90

所以:

safe_angle = 90

但原来的:

joint_angle

仍然是:

120

因为传进去的是副本。


9. 这其实有好处

值传递的一个优点就是:

函数内部乱改参数,不会影响外面的原变量。

例如:

void test(int x)
{
    x = 999;
}

你在外面:

int motor_id = 2;
test(motor_id);

motor_id 不会突然变成 999。

这能减少很多意外修改。


10. 但是,有时候我们就是想改外面的变量

比如:

int speed = 10;

我写一个函数:

void setSpeed(int speed)
{
    speed = 100;
}

然后:

setSpeed(speed);

你可能希望外面的 speed 变成 100。

但值传递下,它不会变。

这时候就需要下一阶段的重要概念:

引用 reference

也就是:

&

不过我们这一课先把“值传递”彻底吃透。


11. 再看一遍完整程序

#include <iostream>

void change(int a)
{
    a = 100;

    std::cout << "Inside: " << a << std::endl;
}

int main()
{
    int x = 5;

    change(x);

    std::cout << "Outside: " << x << std::endl;

    return 0;
}

执行过程:

x = 5
↓
调用 change(x)
↓
把 5 复制给 a
↓
a = 5
↓
a 改成 100
↓
输出 Inside: 100
↓
函数结束
↓
a 消失
↓
回到 main
↓
x 还是 5
↓
输出 Outside: 5

所以:

Inside: 100
Outside: 5

12. 参数名不需要和外面一样

例如:

void printValue(int number)
{
    std::cout << number << std::endl;
}

外面:

int age = 20;

printValue(age);

调用时:

age 的值 20
↓
复制给 number

所以:

number = 20

变量名字不需要一样。


13. 就算名字一样,也还是两个变量

看:

void change(int x)
{
    x = 100;
}

int main()
{
    int x = 5;

    change(x);

    std::cout << x << std::endl;
}

这里函数参数也叫:

x

外面也叫:

x

但是它们仍然不是同一个变量。

可以想象成:

main 房间里的 x = 5

change 房间里的 x = 5

名字相同,不代表同一个东西。

最终还是输出:

5

14. 参数本质上也是函数内部的局部变量

这和上一课正好接上。

void change(int a)

这里:

a

就是 change() 内部的一个局部变量。

只不过它的初始值由调用者传进来。

例如:

change(20);

相当于函数开始时:

a = 20

函数结束后,这个 a 的生命周期结束。


15. 一个容易误解的机器人例子

假设:

void stopMotor(double speed)
{
    speed = 0.0;
}

然后:

int main()
{
    double motor_speed = 100.0;

    stopMotor(motor_speed);

    std::cout << motor_speed << std::endl;
}

你可能觉得:

stopMotor() 不是把速度改成 0 了吗?

但这里只改了函数里的:

speed

所以输出还是:

100

这就是为什么理解值传递非常重要。

以后你看到真实机器人代码时,如果一个函数“明明改了参数,但外面没变”,首先就要检查:

是不是值传递?


16. 值传递的核心图

把这个牢牢记住:

外部变量
x = 5
   │
   │ 复制值
   ▼
函数参数
a = 5
   │
   │ 修改
   ▼
a = 100


外面的 x 仍然 = 5

不是:

x 和 a 指向同一个盒子

这个“同一个盒子”的效果,下一课的引用才会出现。


本课小练习

第 1 题

void change(int a)
{
    a = 20;
}

int main()
{
    int x = 5;

    change(x);

    std::cout << x << std::endl;
}

最后输出什么?

第 2 题

void addTen(int number)
{
    number += 10;

    std::cout << number << std::endl;
}

int main()
{
    int x = 3;

    addTen(x);

    std::cout << x << std::endl;
}

依次输出什么?

第 3 题

为什么:

void change(int a)
{
    a = 100;
}

不能直接改变外面的:

int x = 5;

第 4 题

一句话解释:

什么是值传递?

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐