-
函数与引用
2026-07-14 19:39:19
上一篇我们学了 C++ 的基础语法,所有代码都写在 main 函数里。但真实的程序不可能把所有逻辑塞在一个函数中,我们需要把代码拆分成多个函数,让程序结构更清晰、代码可以复用。
这篇文章除了讲函数的基本用法,还会讲 C++ 中一个非常重要的机制——引用(reference)。学完之后你就能看懂 C++ 代码中函数参数里那些 & 符号了。
¶函数
函数就是一段可以重复调用的代码块,给它一个名字,需要的时候调用就行。
¶定义与调用
一个函数由返回类型、函数名、参数列表和函数体组成:
loading...
return 语句用来返回函数的结果,并且立即结束函数的执行。void 类型的函数没有返回值,不需要写 return(当然你也可以写一个空的 return; 来提前退出函数)。
在 C++ 中,函数必须在调用之前定义。所以在刷算法题时,最简单的做法就是把辅助函数写在 main 函数上面。
¶值传递
C++ 的函数参数默认是值传递,也就是说传进去的是值的副本,在函数内修改参数不会影响外面的变量:
loading...
a 的值传给了 x,但 x 只是 a 的副本,修改 x 不会影响 a。
那如果我确实想在函数里修改外面的变量呢?这就需要用到引用了。
¶引用传递(& 符号)
在参数类型后面加一个 &,就变成了引用传递。引用就是给变量起了个别名,函数内操作的就是原变量本身,而不是副本:
loading...
对比一下:
值传递 void f(int x) —— x 是副本,改了白改
引用传递 void f(int& x) —— x 是原变量的别名,改了就是真改
¶值传递 vs 引用传递:什么时候用哪个
简单记:基本类型传值(副本),容器类型传引用(避免复制)。
基本类型(int、double、bool、char)本身就很小,复制一个 int 几乎没有开销,直接传值就好。除非你确实需要在函数里修改原变量,才用引用。
容器类型(vector、string、map 等)可能包含大量数据,如果传值的话每次调用都要把整个容器复制一遍,非常浪费。所以容器类型一般都传引用。
如果函数只是读取容器、不需要修改它,就加上 const 表示"只读引用":
// 传值:每次调用都复制整个 vector,太浪费了
int sum(vector
nums) { ... } // 引用传递:不复制,但函数内可以修改原容器
int sum(vector
& nums) { ... } // const 引用:不复制,也不允许修改,最安全
int sum(const vector
& nums) { ... } 在刷算法题时,最常用的写法就是 const vector
& 和 vector &,根据需不需要修改来选择。 ¶递归函数传容器的注意事项
这是一个非常容易踩的坑:递归函数中传容器千万别用值传递,否则会超时(TLE)甚至超内存(MLE)。
为什么?因为值传递意味着每次递归调用都会把整个容器复制一份。如果容器有 n 个元素,递归深度是 d,那就会产生 d 份完整拷贝,时间和空间都是灾难。
loading...
上面的回溯算法中,path 用引用传递,所有递归层共享同一个 path,通过 push_back 和 pop_back 来维护状态。如果把 vector
& path 改成 vector path(值传递),每层递归都会复制一份 path,不仅浪费内存,而且逻辑上回溯也不对了。 简单记住:递归函数中,容器类型的参数一律用引用 &。
¶函数重载
C++ 允许多个函数同名,只要参数列表不同(参数个数不同,或参数类型不同),编译器会根据调用时传入的参数自动选择正确的版本。这就是函数重载:
loading...
编译器会根据你传入的参数类型和个数,自动匹配最合适的函数版本。函数重载让接口更简洁——同样是"相加"这个操作,你不需要给它们起不同的名字。
¶小结
这篇讲了两个核心内容:
函数让你把代码拆成可复用的小块,避免重复。引用让你在函数中直接操作原变量,避免不必要的复制。
关键点回顾:
值传递是默认行为,传进去的是副本
加 & 变成引用传递,操作的是原变量
基本类型传值,容器类型传引用
const 引用表示只读,既不复制也不修改
递归函数中容器参数一律用引用 &
函数重载:同名函数,参数不同,编译器自动选择
下一篇我们来学 C++ 中常用的数据结构,包括 vector、string、pair 和结构体。