C++ · 函数
函数定义与调用
逐步比较修改int副本、通过int引用修改原变量和接收函数返回值,用同一组数据检查调用后的变量变化。
函数的输入、处理与返回
想象函数是一台自动售货机:你把钱(参数)投进去,机器按照固定程序(函数体)运作,最后吐出饮料(返回值)。每次投不同面额,就得到不同结果。
何时用?当同一段逻辑要在程序里用好几次,就把它提取成函数,避免复制粘贴。
值传递 vs 引用传递:普通参数是"复印件"——函数里改了不影响外面;加 & 的引用参数是"原件"——函数里改了外面也变。
指针参数:void update(int* p) 接收的是地址的副本,通过 *p 可以修改地址所指的对象;但直接给 p 赋另一个地址,只会改变函数内的指针副本。可用 const 引用传入只读的大对象,减少复制。定义函数还应说明参数约束、返回结果和空指针处理方式。
值传递与引用传递:追踪同一个输入
函数先接收输入,再执行函数体;有返回值时,调用者可以接收结果。下面从n=4开始:普通int参数保存一个副本,修改它不会改变调用者的n;int&参数是调用者对象的另一个名字。先预测n和result,再看执行过程。
| 步骤 | 函数内发生什么 | 调用后n | result |
|---|---|---|---|
| int n = 4; | 尚未调用 | 4 | 尚未声明 |
| int result = byValue(n); | 副本4加2,返回6 | 4 | 6 |
| byReference(n); | 通过引用把n加2 | 6 | 6 |
| n = byValue(n); | 副本6加2,返回8后赋给n | 8 | 6 |
错误一:以为参数名和外面的变量名一样,就一定是同一个对象;判断要看声明的类型和绑定。错误二:以为调用有返回值的函数,原变量会自动更新;要保存结果,应接收返回值或显式赋值。
这里限定普通int值参数,不推广成“所有传值函数都不能改变外部状态”:指针副本仍可能指向外部对象。引用绑定后,对引用赋值是修改所绑定对象,不是换绑定。需要计算一个新结果时,返回值通常清楚;需要修改调用者对象时才选择合适的可写引用。不要返回局部变量的引用。这些固定次数整数运算是O(1),不代表所有函数或所有类型的复制都是O(1)。
运行验证:改副本、改原值、接收结果
#include <iostream>
int byValue(int value) { value += 2; return value; }
void byReference(int& value) { value += 2; }
int main() {
int n = 4;
int result = byValue(n);
std::cout << n << " " << result << "\n";
byReference(n);
std::cout << n << " " << result << "\n";
n = byValue(n);
std::cout << n << " " << result << "\n";
}输出三行4 6、6 6、8 6。result是自己保存的值,不会随n改变。
先自己判断,再展开答案
只把函数里的参数value改名为n,传值就会变成引用吗?
不会,名字不改变int与int&的传参规则;同名也可能是不同对象。
n=10,调用byValue(n)但不接收返回值,n是多少?
还是10。函数返回12,但这个结果没有写回n。
写int& alias=n; alias=9;,这是改n还是让alias改绑到9?
n变成9;alias仍引用原来的n。引用初始化后不能靠赋值换绑定。
调用、引用与参数示例
例1:计算两数之和
#include <iostream>
using namespace std;
// 定义函数:接收两个整数,返回它们的和
int add(int a, int b) {
return a + b;
}
int main() {
int x = 3, y = 5;
cout << add(x, y) << endl; // 输出 8
cout << add(10, 20) << endl; // 输出 30
return 0;
}调用 add(3,5) 时,a=3、b=5 是复印件,函数返回 8;再调用 add(10,20) 时参数换成 10 和 20,函数照样运行,返回 30。
例2:用引用参数交换两个数
#include <iostream>
using namespace std;
// 引用参数:&a、&b 是原件,修改后外部也变
void swap2(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
int main() {
int x = 3, y = 7;
swap2(x, y);
cout << x << " " << y << endl; // 输出 7 3
return 0;
}因为用了引用参数,函数内部对 a、b 的修改直接作用于 main 里的 x 和 y,所以输出变成了 7 3。
例3:修改所指对象与修改指针本身
#include <iostream>
using namespace std;
void update(int* p) {
if (p != nullptr) *p += 1;
p = nullptr; // 只改变本地指针副本
}
int main() {
int x = 4; int* p = &x;
update(p); update(nullptr);
cout << x << " " << (p == &x) << endl;
}输出 5 1。x 经解引用被修改,外面的 p 仍指向 x;函数也检查了空指针。
提示
- 函数名要"见名知意",比如 calcArea(计算面积)比 f1 清晰得多。
- 修改普通 int 值参数只改变副本;若要修改调用者的 int,可用引用参数。指针参数也能通过解引用修改所指对象,见示例。
- 函数要先声明(或定义)再使用,否则编译器看到调用时不认识它。
- 返回值类型写 void 表示函数不返回任何东西,只做操作。
技术参考
范围说明
本站讲解由 InfoCode 编写,不是官方考纲;参考级别是本站映射,不代表官方等级、认证或参赛资格。练习记录不等于掌握或资格。
参考级别:GESP 4 级(本站映射)