函数

1. 函数的作用

  • 易于修改和维护
  • 提高代码重用性
  • 容易阅读和理解

2. 声明函数

返回值类型 函数名(参数类型 参数名, ...);
int add(int a, int b);

也可以省略参数名:

int add(int, int);

3. 定义函数

返回值类型 函数名(参数列表) {
    函数体;
    return 返回值;
}

示例:

int add(int a, int b) {
    return a + b;
}

4. 调用函数

函数名(实参列表);
add(3, 2);

5. 函数声明的位置

当函数定义放在主函数后面时,需要在调用和定义之前先声明:

int add(int a, int b);
// 或
int add(int, int);

6. 函数重载

同一函数名,参数列表不同,可以定义多个函数。
参数列表不同包括:参数个数不同、参数类型不同、参数顺序不同。

7. 函数的参数传递

函数的参数传递有三种方式:值传递、引用传递和指针传递。

7.1 值传递

形参是实参的副本,修改形参不会影响实参。

void f(int x) {
    x++;
}

int a = 5;
f(a);
cout << a; // 输出 5

7.2 引用传递

形参是实参的别名,修改形参就是修改实参。

void f(int& x) {
    x++;
}

int a = 5;
f(a);
cout << a; // 输出 6

7.3 指针传递 / 地址传递

形参是指向实参的指针,通过解引用可以修改实参。

void f(int *x) {
    (*x)++;
}

int a = 5;
f(&a);
cout << a; // 输出 6

8. 数组作为函数参数

数组作为参数传递时,不会创建新的数组副本,而是直接操作原始数组。
在函数内部对数组元素进行的任何修改,都会直接反映到原始数组上,避免了复制整个数组带来的性能开销。

数组名作为实参传递给函数时,它会退化为指向数组首元素的指针。
对于二维数组,传递的是指向第一行,即一个一维数组的指针。
二维数组的参数声明必须至少指定第二维,也就是列数的长度。

8.1 一维数组

// 传递数组名,实际上传递的是指向数组首元素的指针
void f(int arr[], int size);

// 使用指针传递数组,传递一个指向数组首元素的指针
void f(int *arr, int size);

// 使用数组引用传递数组,需要知道数组大小
template <size_t N>
void f(int (&arr)[N]);

注意:void f(int &arr, int size); 表示引用一个 int,不是引用数组。

8.2 二维数组

// 指定行列
void f(int arr[4][5]);

// 省略行,不可省略列
void f(int arr[][5], int row);

// 使用指向一维数组的指针传递数组
void f(int (*arr)[5], int row);

// 使用一维连续内存模拟二维数组
void f(int *arr, int row, int col);

// 使用二维指针传递数组,传递指向数组的指针
void f(int **arr, int row, int col);

说明:

  • int arr[][5] 和 int (*arr)[5] 中,列数 5 不可省略。
  • int *arr 通常用于一维连续内存模拟二维数组,访问时需手动计算下标,例如 arr[i * col + j]。
  • int **arr 通常用于指针数组或动态二维数组。