自定义函数深入

1. 函数的声明与定义

  • 声明(Declaration):告诉编译器函数的名字、返回类型、参数列表。不包含函数体。
  • 定义(Definition):给出函数的具体实现(函数体)。
#include <iostream>
using namespace std;

// 函数声明(原型)
int max(int a, int b);

// 主函数
int main() {
    cout << max(10, 20) << endl;  // 调用
    return 0;
}

// 函数定义
int max(int a, int b) {
    return (a > b) ? a : b;
}

注意:如果定义在调用之前,可以省略单独声明。


2. 函数的形参与实参

  • 形参(Parameter):定义函数时括号内的变量,用于接收数据。
  • 实参(Argument):调用函数时传给函数的具体值或变量。
void printSum(int x, int y) {   // x, y 是形参
    cout << x + y << endl;
}

int main() {
    int a = 5, b = 3;
    printSum(a, b);  // a, b 是实参
    return 0;
}

实参会把自己的值拷贝给形参(取决于传递方式,见下节)。


3. 函数的值传递、引用传递、地址传递

3.1 值传递(Pass by Value)

  • 将实参的值拷贝一份给形参。
  • 函数内部修改形参不影响实参。
void changeVal(int n) {
    n = 100;  // 只修改了拷贝
}

int main() {
    int a = 5;
    changeVal(a);
    cout << a;  // 输出 5,未改变
    return 0;
}

3.2 引用传递(Pass by Reference)

  • 形参是实参的别名,操作形参即操作实参本身。
  • 使用 & 声明。
void changeRef(int &n) {
    n = 100;   // 直接修改原变量
}

int main() {
    int a = 5;
    changeRef(a);
    cout << a;  // 输出 100
    return 0;
}

优点:避免拷贝(尤其适合大对象),可直接修改实参。

3.3 地址传递(Pass by Pointer)

  • 形参为指针,接收实参的地址。
  • 通过解引用操作实参。
void changePtr(int *n) {
    *n = 100;   // 通过地址修改原变量
}

int main() {
    int a = 5;
    changePtr(&a);  // 传地址
    cout << a;      // 输出 100
    return 0;
}

注意:地址传递本质上也是值传递(拷贝了指针的值),但通过该地址可访问原变量。

三种传递方式对比表

传递方式是否修改实参传递内容适合场景
值传递值的拷贝基本类型、小对象
引用传递引用(别名)需修改实参、大对象
地址传递地址(指针)需要指针语义或可为空

4. 函数的作用域

4.1 局部作用域

  • 函数内部定义的变量(包括形参)只能在函数内访问。
  • 函数结束后自动销毁。
void func() {
    int localVar = 10;  // 局部变量
    cout << localVar;   // ✅ 可访问
}

int main() {
    // cout << localVar;  // ❌ 错误,不可访问
    return 0;
}

4.2 全局作用域

  • 定义在所有函数之外的变量,可在函数内直接访问。
  • 若局部变量与全局变量同名,局部会覆盖全局(可使用 :: 访问全局)。
int global = 100;  // 全局变量

void test() {
    int global = 200;        // 局部覆盖
    cout << global << endl;  // 输出 200
    cout << ::global << endl; // 输出 100(:: 访问全局)
}

4.3 静态局部变量(static)

  • 在函数内用 static 修饰,只初始化一次,函数结束后不销毁,下次调用保留上次的值。
void counter() {
    static int count = 0;  // 只初始化一次
    count++;
    cout << "调用次数: " << count << endl;
}

int main() {
    counter();  // 调用次数: 1
    counter();  // 调用次数: 2
    return 0;
}