CC++ & Algorithm

C++形参与实参

困难40
语言版本:C++Python
概述:函数定义时放参数的“小格子”叫形参,调用时往格子里放的东西叫实参。

形参与实参:函数打电话的“小格子”

同学们,你有没有玩过“投币机”?机器上有几个小格子,你往格子里放硬币,机器就会根据硬币数量给你出东西。在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格子里。然后函数就用58计算5×8=40并返回。

再举个生活中的例子:你每天零花钱是10元,你想买一个5元的冰淇淋和一个3元的薯片。你可以写一个“计算总价”函数,调用时传入53,函数返回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

在这个例子中:

  • 形参score1score2average函数里是空的格子。
  • 第一次调用时,实参chinese(88.5)和math(92.0)被复制给形参。
  • 形参只在函数内有效,返回后就不存在了。
  • 实参可以是变量、常量、表达式。

7. 相关指引

理解了形参与实参,你就可以顺畅地使用函数了。接下来可以学习:

  • 函数返回值:函数用return把结果传回主调函数,返回值也是一种特殊的“输出”。
  • 函数重载:可以定义多个同名函数,但形参个数或类型不同,C++会根据实参自动选择。
  • 默认参数:给形参一个默认值,调用时可以省略某些实参。
  • 引用参数:在形参前加&,可以让函数修改外部的实参(就像你把作业递给同学,让他直接修改你的原版)。
  • 作用域与生命周期:形参是局部变量,了解局部变量和全局变量的区别。

记住这个小口诀:形参是坑,实参是萝卜;个数类型要对应,坑里填萝卜。传值复制两不扰,函数内外各归各。 多写代码,多犯错,你很快就能掌握啦!

例题精讲

1单选题

在C++中,定义函数时,写在函数名后面括号里的参数称为?

A实参
B形参
C局部变量
D全局变量
2判断题

在C++中,如果函数参数是基本数据类型(如int、double),在函数内部修改形参的值,会同时影响调用时传入的实参。

3填空题
下面函数用于计算两个整数的乘积,请填写函数定义中的形参列表。

int multiply(___) {
    return a * b;
}
4单选题

以下关于C++函数形参和实参的描述,正确的是?

A函数定义时,形参必须赋初值
B实参可以是常量、变量或表达式,但形参只能是变量
C在函数调用时,实参和形参的个数可以不同
D形参只在函数被调用时分配内存,函数执行结束后自动释放
5判断题

在C++中,当数组作为函数参数时,实际上传递的是数组的首地址,因此在函数内部修改数组元素会改变原数组的内容。