函数的参数就是函数可以获得的细节信息,写在函数名后的括号内。通过参数,调用者可以向函数传递数据,函数根据这些数据执行相应的操作。
在函数声明和函数定义中的参数叫做形式参数(简称形参)。形式参数代表一个类别,即函数可以接受什么样的信息。形式参数就像函数内的其他局部变量一样,在进入函数时被创建,退出函数时被销毁。
如果定义了有参数的函数,那么在调用函数的时候必须传入其所需要的参数。由于该数值决定了函数的实际运算结果,所以我们称调用函数时传入的参数为实际参数(简称实参)。
该过程可以理解为:将实际参数中的数值赋值给形式参数,然后利用形式参数去计算。
下面的代码展示了函数声明、调用和定义中形参与实参的对应关系:
1//函数声明
2void 函数名(参数1类型 形式参数1,参数2类型 形式参数2);
3
4
5int main() {
6 //主函数内调用
7 函数名(实际参数1,实际参数2);
8 return 0;
9}
10
11
12//函数定义
13void 函数名(参数1类型 形式参数1,参数2类型 形式参数2) {
14 函数内代码
15}C++ 中函数传参有两种基本方式:按值传参和引用传参。它们的核心区别在于函数内部的修改是否会影响到外部的实际参数。
按值传递是指将实际参数的值复制一份传递给函数参数。函数内部对参数的修改不会影响到原来的实际参数。
优点:
缺点:
1void foo(int x) {
2 x = 20;
3}
4
5int main() {
6 int a = 10;
7 foo(a);
8 // a的值依然是10
9 return 0;
10}按引用传递是指将实际参数的引用传递给函数参数,函数内部对参数的修改会直接影响到实际参数。引用传参在参数类型后加 & 符号。
优点:
缺点:
1void foo(int &x) {
2 x = 20;
3}
4
5int main() {
6 int a = 10;
7 foo(a);
8 // a的值被修改为20
9 return 0;
10}默认参数允许在函数声明中为参数指定默认值。调用函数时如果没有传入对应的实参,就会使用默认值。如果函数定义与声明分开,默认参数只能在声明中指定。
1#include <iostream>
2using namespace std;
3
4void displayInfo(string name = "Unknown", int age = 0) {
5 cout << "Name: " << name << ", Age: " << age << endl;
6}
7
8int main() {
9 displayInfo(); // 输出:Name: Unknown, Age: 0
10 displayInfo("Bob"); // 输出:Name: Bob, Age: 0
11 displayInfo("Charlie", 30); // 输出:Name: Charlie, Age: 30
12 return 0;
13}默认参数注意事项:
1void func(int a, int b = 10, int c = 20); // 正确
2// void func(int a = 10, int b, int c = 20); // 错误
3
4// 函数声明
5void showMessage(string message = "Hello");
6
7// 函数定义
8void showMessage(string message) {
9 std::cout << message << std::endl;
10}
11
12int main() {
13 showMessage(); // 输出:Hello
14 showMessage("Hi there!"); // 输出:Hi there!
15 return 0;
16}数组参数虽然语法上看起来是按值传递,但实际上传递的是数组的首地址。因此在函数内部修改数组元素时,函数外部的数组也会发生变化。
1#include <iostream>
2using namespace std;
3
4// 使用 int a[] 作为参数的函数,可以修改数组元素
5void modifyArray(int a[], int size) {
6 for (int i = 0; i < size; ++i) {
7 a[i] += 10; // 每个元素加10
8 }
9}
10
11int main() {
12 int arr[] = {1, 2, 3, 4, 5};
13 int size = sizeof(arr) / sizeof(arr[0]);
14
15 // 修改数组元素
16 modifyArray(arr, size);
17
18 // 输出修改后的数组,11 12 13 14 15
19 for (int i = 0; i < size; ++i) {
20 cout << arr[i] << (i + 1 == size ? "\n" : " ");
21 }
22 return 0;
23}数组参数注意事项:
[] 表示传递参数为数组即可,不需要写明具体的数组大小以"交换两个变量的值"为例,分别展示按值传参和引用传参的执行过程:
1void swapByValue(int x, int y) {
2 int temp = x;
3 x = y;
4 y = temp;
5}
6
7int main() {
8 int a = 3, b = 7;
9 swapByValue(a, b);
10 cout << a << " " << b << endl; // 输出:3 7
11 return 0;
12}逐步跟踪:
| 步骤 | 操作 | a(主函数) | b(主函数) | x(函数内) | y(函数内) |
|---|---|---|---|---|---|
| 1 | 初始化 a=3, b=7 | 3 | 7 | - | - |
| 2 | 调用 swapByValue(a, b),复制值 | 3 | 7 | 3 | 7 |
| 3 | temp = x(temp=3) | 3 | 7 | 3 | 7 |
| 4 | x = y | 3 | 7 | 7 | 7 |
| 5 | y = temp | 3 | 7 | 7 | 3 |
| 6 | 函数返回,x 和 y 销毁 | 3 | 7 | - | - |
结果:a 和 b 的值没有改变,因为函数内修改的只是副本。
1void swapByRef(int &x, int &y) {
2 int temp = x;
3 x = y;
4 y = temp;
5}
6
7int main() {
8 int a = 3, b = 7;
9 swapByRef(a, b);
10 cout << a << " " << b << endl; // 输出:7 3
11 return 0;
12}逐步跟踪:
| 步骤 | 操作 | a / x(同一变量) | b / y(同一变量) |
|---|---|---|---|
| 1 | 初始化 a=3, b=7 | 3 | 7 |
| 2 | 调用 swapByRef(a, b),x 是 a 的引用,y 是 b 的引用 | 3 | 7 |
| 3 | temp = x(temp=3) | 3 | 7 |
| 4 | x = y(即 a = b) | 7 | 7 |
| 5 | y = temp(即 b = 3) | 7 | 3 |
| 6 | 函数返回 | 7 | 3 |
结果:a 和 b 的值成功交换,因为 x 和 y 就是 a 和 b 本身。
例题:编写函数找出数组中的最大值和最小值
分析过程:
void findMinMax(int arr[], int n, int &minVal, int &maxVal)1void findMinMax(int arr[], int n, int &minVal, int &maxVal) {
2 minVal = arr[0];
3 maxVal = arr[0];
4 for (int i = 1; i < n; ++i) {
5 if (arr[i] < minVal) minVal = arr[i];
6 if (arr[i] > maxVal) maxVal = arr[i];
7 }
8}
9
10int main() {
11 int a[] = {4, 1, 7, 3, 9};
12 int minV, maxV;
13 findMinMax(a, 5, minV, maxV);
14 cout << "最小值:" << minV << " 最大值:" << maxV << endl;
15 // 输出:最小值:1 最大值:9
16 return 0;
17}关键思路: 当函数需要"返回"多个值时,用引用传参让函数直接修改调用者的变量。
&,导致函数内交换了但外部变量不变void func(int a[10]) 中的 10 会被编译器忽略,容易产生误解,应写成 int a[]sizeof 求长度,必须额外传一个 int n 参数void f(int a = 1, int b, int c = 3) 是错误的