函数的参数传递-引用传递

一、引用传递的概念

上节课学习了值传递,我们知道值传递是单向传递,形参和实参占用不同的内存空间,形参的改变不会影响实参。

如果需要在子函数中对形参的更改影响到实参,就需要使用引用传递。

二、引用的基本概念

引用是一种特殊类型的变量,可以被认为是另一个变量的别名。就好比 Windows 系统中的快捷方式图标,通过引用名访问变量与通过原变量名访问变量的效果完全一样。

引用的声明
类型名 &引用名 = 已存在的变量;

示例:

int a = 2;
int &ra = a;   // ra 是 a 的引用(别名)Code language: JavaScript (javascript)

注意:真正的标识符是 ra,不是 &ra。& 在这里是引用声明符,不是取地址运算符。

引用的规则
  1. 声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。
  2. 一旦一个引用被初始化,就不能改为指向其他对象。
  3. 一个引用从诞生开始就必须确定是哪个变量的别名,并且始终只能作为该变量的别名,不能另作他用。
int a = 2, b = 4;
int &ra = a;   // ra 是 a 的别名
ra = b;        // 这不是让 ra 指向 b,而是将 b 的值赋给 a
cout << a;     // 输出 4Code language: JavaScript (javascript)

三、引用作为形参(引用传递)

如果将引用作为形参,函数调用时发生的参数传递就是引用传递。引用传递时,形参是实参的别名,形参和实参占用同一块内存空间。对形参的任何操作,实质上就是对实参的操作。

语法形式
返回类型 函数名(类型名 &形参名1, 类型名 &形参名2, ...)
{
    语句序列
}

四、示例:用引用传递实现交换两个整数

#include <iostream>
using namespace std;

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

int main()
{
    int a = 2;
    int b = 4;
    cout << "交换前 a,b " << a << " " << b << endl;   // 输出 2 4
    swap(a, b);
    cout << "交换后 a,b " << a << " " << b << endl;   // 输出 4 2
    return 0;
}Code language: PHP (php)

分析:

  1. main 中 a = 2, b = 4。
  2. 调用 swap(a, b) 时,形参 int &a 是实参 a 的别名,int &b 是实参 b 的别名。
  3. swap 函数内部交换形参 a 和 b 的值,实际上交换的就是 main 中实参 a 和 b 的值。
  4. swap 执行完毕,main 中的 a 和 b 已经被成功交换。

五、代码示例

以下代码演示了引用传递的各种应用场景:

#include <iostream>
using namespace std;

// 示例1:引用传递交换两个变量
void swap(int &x, int &y)
{
    int temp = x;
    x = y;
    y = temp;
}

// 示例2:引用传递修改多个值
void divide(int dividend, int divisor, int &quotient, int &remainder)
{
    quotient = dividend / divisor;
    remainder = dividend % divisor;
}

// 示例3:引用传递用于输入参数
void input(int &x)
{
    cout << "请输入一个整数:";
    cin >> x;
}

// 示例4:引用传递用于累加
void accumulate(int &sum, int value)
{
    sum += value;
}

// 示例5:引用作为返回值(返回后不能引用局部变量)
int global = 100;
int& getGlobal()
{
    return global;
}

// 示例6:常量引用(防止在函数内修改实参)
void printArray(const int &size)
{
    // size = 10;   // 错误:size 是常量引用,不能修改
    cout << "size = " << size << endl;
}

// 示例7:结构体引用传递
struct Point
{
    int x;
    int y;
};

void movePoint(Point &p, int dx, int dy)
{
    p.x += dx;
    p.y += dy;
}

// 示例8:值传递 vs 引用传递对比
void byValue(int x)
{
    x = 999;
}

void byReference(int &x)
{
    x = 999;
}

int main()
{
    // 测试交换
    int a = 2, b = 4;
    cout << "交换前 a=" << a << ", b=" << b << endl;
    swap(a, b);
    cout << "交换后 a=" << a << ", b=" << b << endl << endl;

    // 测试多值返回
    int q, r;
    divide(17, 5, q, r);
    cout << "17 / 5 = " << q << " 余 " << r << endl << endl;

    // 测试输入
    int num;
    input(num);
    cout << "你输入的是:" << num << endl << endl;

    // 测试累加
    int sum = 0;
    accumulate(sum, 10);
    accumulate(sum, 20);
    accumulate(sum, 30);
    cout << "累加结果:" << sum << endl << endl;

    // 测试引用返回值
    getGlobal() = 200;
    cout << "global = " << global << endl << endl;

    // 测试常量引用
    int sz = 5;
    printArray(sz);
    cout << endl;

    // 测试结构体引用传递
    Point pt = { 1, 2 };
    cout << "移动前 pt=(" << pt.x << "," << pt.y << ")" << endl;
    movePoint(pt, 10, 20);
    cout << "移动后 pt=(" << pt.x << "," << pt.y << ")" << endl << endl;

    // 测试值传递 vs 引用传递
    int test = 5;
    byValue(test);
    cout << "byValue 后 test=" << test << endl;   // 仍为 5
    byReference(test);
    cout << "byReference 后 test=" << test << endl;   // 变为 999

    return 0;
}Code language: PHP (php)

六、值传递与引用传递的对比

特性值传递引用传递
形参类型普通变量引用变量(类型名 &)
内存关系形参和实参占用不同内存形参是实参的别名,共用同一内存
传递方向单向(实参 → 形参)双向(形参修改影响实参)
初始化用实参的值初始化形参绑定到实参
适用场景不需要修改实参需要修改实参、大型对象避免复制
语法void func(int a)void func(int &a)

七、注意事项

  • 引用必须在声明时初始化,且一旦绑定就不能更改指向。
  • 引用传递中,形参是实参的别名,对形参的操作直接影响实参。
  • 如果不需要在函数内修改实参,但希望避免大型对象的复制开销,可以使用常量引用(const 类型名 &)。
  • 不要返回局部变量的引用,因为局部变量在函数结束后被销毁,引用将指向无效内存。
  • 引用作为形参时,函数调用时不需要写 &,直接传变量名即可。编译器自动进行引用绑定。
  • 引用传递比指针传递更安全、更直观,是 C++ 中推荐的参数传递方式。

八、常见错误

1. 引用未初始化
int &r;        // 错误:引用必须初始化Code language: HTML, XML (xml)
2. 返回局部变量的引用
int& func()
{
    int x = 10;
    return x;   // 危险:x 被销毁后引用无效
}Code language: JavaScript (javascript)
3. 误以为引用可以重新绑定
int a = 1, b = 2;
int &r = a;
r = b;          // 这是将 b 的值赋给 a,不是让 r 指向 bCode language: JavaScript (javascript)
4. 常量引用被修改
void func(const int &x)
{
    x = 10;     // 错误:常量引用不能修改
}Code language: JavaScript (javascript)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注