跳转至

函数传参:值、指针与引用(先不看)

值传递

普通 int 参数,接收到实参的值,修改的是副本。

#include <iostream>

using namespace std;

void fun(int x) {
    x += 5;
}

int main() {
    int y = 0;
    fun(y);

    cout << y; // 输出0

    return 0;
}

fun 里的 x,与 main 里的 y 是两个独立变量。

不要由此认定“值传递一定慢,引用一定快”。先看需不需要修改原对象,再看数据类型和使用场景。

指针传参

把地址传进去,通过指针修改原变量。

#include <iostream>

using namespace std;

void fun(int *x) {
    *x += 5;
}

int main() {
    int y = 0;
    fun(&y);

    cout << y; // 输出5

    return 0;
}

调用时传 &y,函数里通过 *x 修改 y。这里要求传入的指针指向有效的 int 对象。

指针本身,也是按值传进去的。 改指针的指向,与改它指向的数据,不是一回事。

引用传参

参数直接成为实参的别名。

#include <iostream>

using namespace std;

void fun(int &x) {
    x += 5;
}

int main() {
    int y = 0;
    fun(y);

    cout << y; // 输出5

    return 0;
}

定义参数时写 int &x,调用时仍然写 fun(y),不用给 y 加取地址符。

这里的 y 要先有确定的值,因为函数中 x += 5 会读取旧值再加 5。

交换两个变量

值传递,交换的是副本

void my_swap(int a, int b) {
    int t = a;
    a = b;
    b = t;
}
int a = 1, b = 2;
my_swap(a, b);

cout << a << ' ' << b; // 输出1 2

引用传参,才能在这里修改原来的两个变量

void my_swap(int &a, int &b) {
    int t = a;
    a = b;
    b = t;
}
int a = 1, b = 2;
my_swap(a, b);

cout << a << ' ' << b; // 输出2 1

两组例子分别运行,不要把这两个同名版本同时抄进同一份程序。

改指针,与改指向的数据

#include <iostream>

using namespace std;

void f(char *a, char *b) {
    a = b;
    (*a)++;
}

int main() {
    char c1 = 'A', c2 = 'a';
    char *p1 = &c1, *p2 = &c2;
    f(p1, p2);

    cout << c1 << ' ' << c2; // 输出A b
    cout << '\n' << (p1 == &c1); // 输出1,p1仍指向c1

    return 0;
}

a = b 只改变函数内指针副本 a 的指向,不会把 main 里的 p1 改掉。

随后 (*a)++ 修改的是 c2,所以 c2 从小写 a 变成小写 b。

输出字符变量的地址

char c = 'a';
cout << static_cast<void*>(&c);

cout 对 char* 有特殊处理,会把它当成 C 风格字符串。

想输出地址,就先转成 void*。否则拿单个字符的地址当字符串输出,可能一直读到后面的内存。

数组参数

void change(int a[], int n) {
    for (int i = 0; i < n; i++) a[i]++;
}

这里的数组参数,实际按指向首元素的指针处理,不会复制整个数组。

修改 a[i],会修改调用者数组中的对应元素。长度需要另外传入,不能在函数里用 sizeof a 得到整个数组大小。