共计 2163 个字符,预计需要花费 6 分钟才能阅读完成。
函数调用的基本概念
在 C ++ 中,函数调用是程序执行的基本单位之一。简单来说,函数调用就是让程序跳转到函数定义的地方去执行代码,然后再返回到调用点继续执行。这个过程涉及到几个关键步骤:

- 参数传递:调用函数时,需要把实参传递给形参
- 栈帧创建:每次函数调用都会在调用栈上创建一个新的栈帧
- 执行函数体:执行函数内部的代码
- 返回值处理:如果有返回值,需要将结果返回给调用者
- 栈帧销毁:函数执行完毕后,对应的栈帧会被销毁
参数传递方式详解
C++ 中有三种主要的参数传递方式,各有特点和适用场景。
1. 值传递
值传递是最简单的参数传递方式,函数收到的是参数的副本。对副本的修改不会影响原始变量。
void increment(int num) {num++; // 只修改副本}
int main() {
int a = 5;
increment(a);
cout << a; // 输出仍然是 5
return 0;
}
- 优点:简单直观,不会意外修改原始数据
- 缺点:需要复制数据,对于大型对象可能影响性能
- 适用场景:基本数据类型、不需要修改原始数据的情况
2. 引用传递
引用传递传递的是变量的别名,函数内对参数的修改会影响原始变量。
void increment(int &num) {num++; // 修改原始变量}
int main() {
int a = 5;
increment(a);
cout << a; // 输出变为 6
return 0;
}
- 优点:避免复制开销,可以直接修改原始数据
- 缺点:可能意外修改原始数据
- 适用场景:需要修改原始数据、大型对象传递
3. 指针传递
指针传递传递的是变量的地址,通过解引用操作可以访问和修改原始变量。
void increment(int *num) {(*num)++; // 通过指针修改原始变量
}
int main() {
int a = 5;
increment(&a);
cout << a; // 输出变为 6
return 0;
}
- 优点:灵活,可以处理 NULL 指针
- 缺点:语法稍复杂,有指针安全风险
- 适用场景:需要明确表示参数可为空、C 风格接口兼容
代码示例集合
示例 1:交换两个变量的值
// 值传递(无法实际交换)void swapByValue(int a, int b) {
int temp = a;
a = b;
b = temp;
}
// 引用传递(正确实现)void swapByRef(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
// 指针传递(正确实现)void swapByPtr(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
示例 2:大型对象传递效率比较
struct BigData {int data[1000];
};
// 值传递(效率低)void processByValue(BigData b) {// 处理数据}
// 引用传递(效率高)void processByRef(const BigData &b) {// 处理数据(const 确保不会意外修改)}
示例 3:返回多个值
// 通过引用参数返回多个值
void calculate(int a, int b, int &sum, int &product) {
sum = a + b;
product = a * b;
}
int main() {
int x = 5, y = 3;
int s, p;
calculate(x, y, s, p);
cout << "Sum:" << s << ", Product:" << p;
return 0;
}
常见错误分析
- 忘记取地址符
void func(int *ptr);
int main() {
int x = 10;
func(x); // 错误:需要传递 &x
return 0;
}
- 引用传递修改了不想修改的变量
void print(const string &s); // 应该用 const 引用
void print(string &s) { // 非 const 引用可能限制调用
cout << s;
}
- 返回局部变量的引用 / 指针
int& badFunction() {
int x = 10;
return x; // 错误:x 将被销毁
}
- 混淆指针和引用语法
int a = 5;
int &ref = a;
int *ptr = &a;
*ref; // 错误:引用不需要解引用
&ptr; // 错误:获取的是指针的地址
性能优化建议
- 对于小型基本类型(int, float 等),值传递通常足够高效
- 对于大型对象,使用 const 引用传递避免复制
- 需要修改原始数据时,使用非 const 引用
- 高频调用的简单函数可声明为 inline
- 避免在循环内部创建临时对象
// 优化前
for (int i = 0; i < 1000; i++) {processBigData(BigData()); // 每次循环构造临时对象
}
// 优化后
BigData data;
for (int i = 0; i < 1000; i++) {processBigData(data); // 复用同一对象
}
实践练习
实现一个函数集合,处理学生成绩:
- 使用值传递实现计算平均分
- 使用引用传递实现最高分查找
- 使用指针传递实现成绩调整
- 比较不同实现方式的性能和便利性
struct Student {
string name;
float scores[5];
};
// 你的实现代码...
总结
函数调用是 C ++ 编程的基础,理解不同的参数传递方式对写出高效、安全的代码至关重要。值传递简单安全但可能有性能开销,引用传递高效但需要小心使用,指针传递灵活但风险较高。根据具体场景选择合适的传递方式,并注意避免常见的错误模式。通过实际练习和性能测试,可以更好地掌握这些概念。
正文完
