知用网
第二套高阶模板 · 更大气的阅读体验

函数参数传值和传引用到底有什么区别?

发布时间:2025-12-09 13:09:55 阅读:356 次

写代码的时候,你有没有遇到过这样的情况:在函数里改了一个变量,结果外面的值也被动了?或者相反,明明改了却没变?这背后很可能就是传值和传引用在“作怪”。

传值:各过各的,互不干扰

传值就像复印一份文件。你在函数里拿到的是原数据的一份副本,怎么折腾都不会影响原件。比如在 C 语言里,基本类型默认就是传值:

void changeValue(int x) {
    x = 100;
    printf("函数内 x = %d\n", x);
}

int main() {
    int a = 10;
    changeValue(a);
    printf("函数外 a = %d\n", a);
    return 0;
}

输出结果是:

函数内 x = 100
函数外 a = 10

看,函数里的修改对 a 没有任何影响。这就是传值的典型表现——安全但可能浪费内存,尤其是复制大对象时。

传引用:牵一发而动全身

传引用更像是共享同一个文档链接。你拿到的不是副本,而是原始数据的位置。改了它,所有用这个引用的地方都会看到变化。C++ 支持直接传引用:

void changeRef(int& x) {
    x = 200;
}

int main() {
    int b = 20;
    changeRef(b);
    printf("函数外 b = %d\n", b); // 输出 200
    return 0;
}

这里 b 的值真的被改成了 200。这种机制效率高,避免了复制开销,但也容易“误伤”原数据,调试起来有时挺头疼。

Python 是个“混搭”高手

Python 不像 C++ 那样明确区分 & 符号,但它其实也有类似行为,只是规则藏得深。它按“对象可变性”来决定:

不可变对象(比如整数、字符串)看起来像传值:

def modify_num(x):
    x = 50

num = 10
modify_num(num)
print(num)  # 还是 10

可变对象(比如列表),就表现出传引用的效果:

def modify_list(lst):
    lst.append(4)

my_list = [1, 2, 3]
modify_list(my_list)
print(my_list)  # 变成 [1, 2, 3, 4]

很多人初学 Python 时在这里踩坑。你以为传的是值,结果原列表被改了。想避免?可以手动传副本:modify_list(my_list.copy())

JavaScript 的“中间路线”

JS 所有参数都是传值,但对象类型传的是“引用的值”,听起来绕,其实就像把门牌号复印了一份给人。你拿门牌号能进去改屋子里的东西,但换门牌不影响原来的那份。

function changeObj(obj) {
    obj.name = '新名字';
}

let user = {name: '老王'};
changeObj(user);
console.log(user.name); // 新名字

但如果在函数里重新赋值 obj,那就断链了:

function reassignObj(obj) {
    obj = {name: '完全新建'};
}

reassignObj(user);
console.log(user.name); // 还是 '新名字'

因为这只是改了“本地门牌号”,不影响原来的 user 指向。

实际开发中的小建议

如果你写的函数只是读数据,随便传。但要是会修改,最好在文档里写清楚,或者干脆设计成返回新值,而不是改动输入。这样别人调用时心里更有底,也不容易出 bug。

理解传值和传引用,不是为了背概念,而是让你更清楚自己的代码到底在动谁的数据。下次改完函数发现外面的变量“莫名其妙”变了,别急着骂环境,先看看是不是参数传递方式惹的祸。