C++形参与实参
困难40形参与实参:函数打电话的“小格子”
同学们,你有没有玩过“投币机”?机器上有几个小格子,你往格子里放硬币,机器就会根据硬币数量给你出东西。在C++函数里,也有这样的“小格子”,它们就是形参(形式参数);你打电话时真正放进去的硬币,就是实参(实际参数)。简单来说,形参是函数定义时挖的“坑”,实参是调用时往坑里填的“萝卜”。每个坑只能填对应大小的萝卜,填错了,函数就会罢工。
1. 形参:函数里的“空格子”
形参写在函数定义的小括号里,就像在说:“这个函数需要几个值才能工作,我现在先规定好这些值叫什么名字、是什么类型。” 形参是空的,等着被调用时填入数据。
看一个函数定义:
int box(int length, int width) { // length和width就是形参,是两个格子
return length * width; // 用格子里的值计算面积
}
这里box函数定义了两个形参:length(长度)和width(宽度),都是int类型。它们就像两个空的小格子,等着调用时往里放数字。如果调用时不填,函数就没法计算面积。
形参的名字只在函数内部有效,比如你可以在函数里写length = length + 1,但函数外面根本看不见length这个变量——因为格子只在函数运行期间存在。
生活例子:去食堂打饭,窗口有“三两米饭”和“一份菜”两个格子。你告诉阿姨“三两米饭、一份西红柿炒蛋”,阿姨才会往你饭盒里装东西。这里的“三两米饭”和“一份菜”就是形参的规定。
2. 实参:你真正放进去的“硬币”
实参是你在调用函数时,放在小括号里的具体值。它可以是常量、变量、表达式,甚至另一个函数的返回值(等你学了函数嵌套就明白了)。
当你调用box函数时:
int area = box(5, 8); // 5和8就是实参
实参5被放进形参length的格子里,8放进width格子里。然后函数就用5和8计算5×8=40并返回。
再举个生活中的例子:你每天零花钱是10元,你想买一个5元的冰淇淋和一个3元的薯片。你可以写一个“计算总价”函数,调用时传入5和3,函数返回8元,然后你就能判断自己钱够不够。
实参可以是变量,比如:
int my_len = 5;
int my_wid = 8;
int area2 = box(my_len, my_wid); // 实参是两个变量:my_len和my_wid
实参也可以是表达式,比如:
int a = 10, b = 20;
int result = box(a + 1, b - 5); // 先计算a+1=11,b-5=15,然后传给length和width
注意:实参的值先被计算出来,再传给形参。就像你先在纸上算好结果,再填进表格里。
3. 形参和实参必须“一一对应”
就像考试时,选择题的答案必须涂在对应题号的位置上,实参的顺序、个数、类型必须与形参完全匹配。
- 个数匹配:形参有2个,实参也必须传2个。传1个或3个都会报错。
- 类型匹配:形参是
int,你就不能传一个字符串(比如"hello")或一个小数(比如3.14,虽然有些编译器会悄悄截断,但最好精确匹配)。 - 顺序匹配:第一个实参传给第一个形参,第二个实参传给第二个形参。如果你写
box(8, 5),那么length得到8,width得到5,结果还是40,因为乘法交换律不影响。但如果函数是求差(比如return length - width),顺序错了就麻烦了。
常见错误1:个数不对
int wrong_area = box(5); // 错误!只传了一个实参,但形参需要两个
常见错误2:类型不匹配
double result = box(2.5, 3); // 虽然有些编译器会警告并自动转换,但不推荐这样写。最好严格匹配int类型
4. 传值:形参是实参的“复印件”
C++中默认的传参方式是传值(pass by value)。这意味着函数被调用时,实参的值会被复制一份给形参。函数内部对形参的任何修改,都不会影响外面的实参。就像你把作业给同学抄,同学在复印件上乱画,你的原版作业还是干净的。
看这个例子:
#include <iostream>
using namespace std;
void change(int x) { // x是形参,接收一个int的副本
x = 100; // 修改副本,不影响外面的变量
}
int main() {
int x = 5; // 主函数里的变量x,值为5
change(x); // 将5复制给形参x,函数内修改形参为100
cout << x << endl; // 输出还是5,因为外面的x没变
return 0;
}
你可能会疑惑:为什么要把变量名都叫x?其实它们完全是两个不同的变量,只是名字相同而已。形参x只在change函数里存在,主函数的x在主函数里存在,互不干扰。为了更清晰,你可以把形参改成别的名字:
void change(int y) { // 形参叫y,避免混淆
y = 100;
}
// 调用时:change(x); // 把x的值5复制给y,y变成100,x还是5
生活例子:你想让同桌帮你算24点,你在一张纸上写下数字(实参),同桌把它抄到自己的草稿纸上(形参),然后草稿纸上乱涂乱画,你的原纸纹丝不动。
为什么要这样设计? 保证函数外部的数据安全。如果你不想让函数改变外部的变量,就使用传值。如果你想在函数里改变外部的变量,就需要学习“引用参数”(用&符号),那是更高级的内容。
5. 形参的作用域:只在函数内部有效
形参在函数定义时创建,函数结束后自动销毁。就像食堂窗口的格子,阿姨打完饭就擦干净,下一轮重新填。
常见错误3:认为形参可以在函数外使用
void func(int a) {
a = 10;
}
int main() {
func(5);
cout << a << endl; // 错误!a只存在于func函数内,这里无法访问
return 0;
}
常见错误4:感觉函数内改了形参就以为外面也会变
我们已经讲了传值的特点,新手常常以为change(x)能改变x,结果发现没变。记住:形参是复印件,改复印件不影响原件。
6. 完整可运行的示例:计算考试成绩平均分
我们来写一个完整的程序,用函数计算两门考试的平均分。注意形参和实参的使用。
#include <iostream>
using namespace std;
// 函数:计算两个分数的平均分
// 形参:score1(第一门分数),score2(第二门分数)
double average(double score1, double score2) {
double sum = score1 + score2; // 求和
double avg = sum / 2.0; // 求平均数
return avg; // 返回结果
}
int main() {
double chinese = 88.5; // 语文成绩
double math = 92.0; // 数学成绩
// 调用函数,实参是chinese和math两个变量
double result = average(chinese, math);
cout << "平均分是:" << result << endl; // 输出90.25
// 也可以直接用常量作为实参
cout << "另一组平均分:" << average(75.0, 80.5) << endl; // 输出77.75
// 还可以用表达式作为实参
double bonus = 5.0;
cout << "加分后平均分:" << average(chinese + bonus, math) << endl; // 93.5+92=185.5,平均92.75
return 0;
}
运行结果:
平均分是:90.25
另一组平均分:77.75
加分后平均分:92.75
在这个例子中:
- 形参
score1和score2在average函数里是空的格子。 - 第一次调用时,实参
chinese(88.5)和math(92.0)被复制给形参。 - 形参只在函数内有效,返回后就不存在了。
- 实参可以是变量、常量、表达式。
7. 相关指引
理解了形参与实参,你就可以顺畅地使用函数了。接下来可以学习:
- 函数返回值:函数用
return把结果传回主调函数,返回值也是一种特殊的“输出”。 - 函数重载:可以定义多个同名函数,但形参个数或类型不同,C++会根据实参自动选择。
- 默认参数:给形参一个默认值,调用时可以省略某些实参。
- 引用参数:在形参前加
&,可以让函数修改外部的实参(就像你把作业递给同学,让他直接修改你的原版)。 - 作用域与生命周期:形参是局部变量,了解局部变量和全局变量的区别。
记住这个小口诀:形参是坑,实参是萝卜;个数类型要对应,坑里填萝卜。传值复制两不扰,函数内外各归各。 多写代码,多犯错,你很快就能掌握啦!
例题精讲
在C++中,定义函数时,写在函数名后面括号里的参数称为?
在C++中,如果函数参数是基本数据类型(如int、double),在函数内部修改形参的值,会同时影响调用时传入的实参。
下面函数用于计算两个整数的乘积,请填写函数定义中的形参列表。
int multiply(___) {
return a * b;
}以下关于C++函数形参和实参的描述,正确的是?
在C++中,当数组作为函数参数时,实际上传递的是数组的首地址,因此在函数内部修改数组元素会改变原数组的内容。