基础

C++ 函数:完整图景

一句话答案:函数是一段有名字的代码,带类型的输入(参数)和一个类型的输出(返回值)。调用它,就是带着具体输入跑一遍这段代码,然后把结果交回来。

结构

int add(int a, int b) {   // 返回类型、名字、参数表
    return a + b;         // 函数体,以返回一个 int 结束
}

这一行有四处要读:int 是交出什么,add 是名字,int a, int b 是输入,return 产生输出。没有返回值的函数声明为 void。

调用就是代入

#include <iostream>
using namespace std;

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

int square(int x) {
    return x * x;
}

int main() {
    cout << add(2, 3) << endl;         // 5
    cout << square(add(1, 1)) << endl; // (2)^2 = 4 —— 调用里套调用
    return 0;
}

第二行才是重点:函数调用本身就是一个值,所以它出现在任何能放字面量的地方。函数可组合性就来自这里。

参数是拷贝

这是关于 C++ 函数最重要的一个事实:

#include <iostream>
using namespace std;

void tryToChange(int n) {
    n = 999;          // 只改了本地拷贝
}

int main() {
    int x = 5;
    tryToChange(x);
    cout << x << endl;   // 还是 5
    return 0;
}

真要改调用方的变量,必须传地址(指针)或引用。三种传法的完整对比(带图)在传值、指针还是引用。

返回 vs 打印

返回值的函数能参与表达式,打印的不行:

#include <iostream>
using namespace std;

int doubled(int n) { return n * 2; }

void printed(int n) { cout << n * 2 << endl; }

int main() {
    int total = doubled(10) + 1;   // 可以:doubled() 是一个值
    cout << total << endl;
    printed(10);                   // 可以,但没法复用
    return 0;
}

家规:在函数里算(return),在 main 里打印。这样函数既可测又可复用。

作用域:名字住在哪

#include <iostream>
using namespace std;

int counter = 0;        // 全局:到处可见

int bump() {
    int local = 5;      // 局部:只在这次调用中存在
    counter++;
    return counter + local;
}

int main() {
    cout << bump() << endl;   // 6
    cout << bump() << endl;   // 7 —— 全局活下来了
    // cout << local;         // 错误:local 不在此作用域
    return 0;
}

优先用局部变量:函数需要什么就作为参数传进去,产出什么就返回出来。全局变量很方便,却会悄悄让代码难以推理。

到底为什么要拆函数

三个 bug

练习:素数判断和最大公约数用辅助函数写都会更清爽。接着读:递归,然后是传参方式。