🔷 第六章 函数
📄 一句话概括

auto 变量 = 默认的局部变量:住在栈上,函数被调用时出生、函数返回时销毁。"自动"指的是自动分配、自动回收——你不用管,进出函数时系统自动打理。每次调用都是一间全新的房,所以别指望它记住上次的值。

📝 本节和前面几节的关系

6.7 画了四个存储类别的全景,从这一节开始逐个落地。auto 是最"平常"的那个——你写的每个普通局部变量都是 auto(哪怕从来不打这个词)。它和内存里的"栈"绑在一起,第 7 章讲指针时会反复回到这个话题。

一、auto 是什么

void f() {
    int a = 0;         // 这个 a 就是 auto 变量(不用写 auto)
    auto int b = 1;    // 老写法:显式写出来,完全等价
}

两种写法完全等价。现代 C++ 里没人再显式写 auto(原因见下面"⚠️ 别搞混")。

二、"自动"体现在哪里

时机 系统做的事
进入函数 在栈上给 a 分配空间(自动分配)
函数执行 a 正常读写
函数返回 立刻回收这块空间(自动回收),值随之消失

"自动"就是"自动分配 + 自动回收"。对比第 7 章堆上的内存——那才需要你自己申请、自己归还,还容易忘。

三、动手 Demo:每次调用都是新的

#include <iostream>
using namespace std;

void f() {
    int a = 0;              // auto 变量:每次调用都重新出生
    a++;
    cout << "f 里 a = " << a << endl;
}

int main() {
    f();                    // a 出生(0)→ a++ → 1
    f();                    // a 又出生(0)→ a++ → 1
    f();
    return 0;
}

看到什么算成功:

f 里 a = 1
f 里 a = 1
f 里 a = 1

三行全是 1——如果 a 能"记住上次",第三行就该是 3。它记不住,因为它每次都重生。(想记住,就得请出 6.7.2 的 static。)

30 秒实验:把 int a = 0; 改成 int a;(不初始化),运行——输出可能是 1,也可能是任何数(2.3.2 的垃圾值)。多跑几次,甚至同一次程序里不同调用都不一样。这正说明"栈上的空间是复用的、没人替你清零",所以 auto 变量必须初始化。

四、auto 的两条重要限制

  1. 活不过函数——函数一返回,值就没了。想让它活到程序结束,用 static(下一节)。
  2. 别留着它的地址——如果你把函数里定义的变量的地址(或数组)交给外面,拿到的是"已经退房房间的钥匙"。本章先钉一颗钉子:函数里的东西,出了函数就别再找它——第 7 章的指针会详细讲这个灾难(悬垂指针)。

⚠️ 别搞混:C++11 之后,auto 关键字被重新定义为"让编译器自动推导类型"(如 auto x = 3.14; 会让 x 是 double)。教材这里讲的是旧的存储类别含义——同一个词,两个含义。本章按教材理解;以后看到别人代码里的 auto x = ...,那是"类型推导",跟"住栈上"没关系。

五、常见误区

  1. "必须写 auto 关键字"——不用。函数里不写任何存储类别的变量默认就是 auto。
  2. "auto 变量会记住上次的值"——不会,每次调用都是新的(这是它和 static 的分水岭)。
  3. "auto 变量不初始化也没关系"——危险。栈空间是复用的,未初始化就是垃圾值。
  4. "auto 变量的地址可以留着以后用"——绝对不行。函数返回后那块空间就被回收(可能立刻被别的变量占用)。这是第 7 章的伏笔。
自测三问(点开对答案) 1. auto 变量住在哪、活多久?——住在栈上,随函数进入而生、返回而死。 2. "自动"指什么?——自动分配和自动回收内存,不用程序员操心。 3. 为什么不能在函数外使用函数内 auto 变量的地址?——函数返回后那块内存已被回收,地址失效(悬垂指针)。

相关笔记