变量存储位置由声明方式和存储期决定:函数内无static/extern的变量在栈;含new/malloc的在堆;文件作用域或带static/extern的在数据段;const字符串字面量等在.rodata。

变量声明时默认分配在栈上
除非你显式用 new 或 malloc,否则局部变量、函数参数、临时对象都落在栈里。栈是自动管理的:函数进,空间压入;函数出,整块弹出——快,但没商量。
常见错误现象:return &x; 返回局部变量地址,调用方拿到的是已失效的栈地址,读写必崩或静默错乱。
- 栈空间小(通常几 MB),递归过深或定义超大数组(比如
int a[1000000];)直接触发stack overflow - 栈上对象构造/析构严格按作用域顺序,不能手动控制生命周期
- 没有零初始化保证:
int x;在栈上是未定义值,而static int x;才是 0
堆内存靠 new / delete 显式申请释放
堆是程序运行期动态分配的区域,大小受系统限制(GB 级),但管理成本高。每次 new 都要查空闲块、拆分、更新元数据;delete 还要合并、标记——慢,还容易出错。
使用场景:对象生命周期超出当前作用域、大小编译期未知(如用户输入决定数组长度)、需要共享所有权(配合智能指针)。
- 忘记
delete→ 内存泄漏;多删一次 →double free崩溃 -
new int[10]必须配delete[],混用delete是未定义行为 - 异常可能跳过
delete:裸指针 + 异常 = 大概率泄漏,必须用std::unique_ptr或std::shared_ptr
全局/静态变量存在数据段,不是栈也不是堆
很多人误以为“不写 new 就是栈”,其实 int global_x;、static int s;、const char* s = "hello"; 全部在数据段(data/bss/rodata)。它们在程序启动时分配,结束时释放,不参与栈帧也不走堆管理器。
关键差异:static 局部变量虽在函数内声明,但存储位置和生命周期都等同于全局变量——只初始化一次,跨多次调用保留值。
- 数据段内容可读可写(除字符串字面量在
.rodata只读),改"hello"[0] = 'H'会 crash - 未初始化的全局变量(
int g;)自动清零;未初始化的栈变量(int x;)则不是 - 模板静态成员、函数内
static对象的首次初始化是线程安全的(C++11 起),但注意潜在延迟构造开销
怎么快速判断一个变量在哪?看声明位置 + 关键字
别猜,看代码本身。栈/堆/数据段的归属,完全由变量的**声明方式**和**存储期**决定,和类型无关(std::string 对象本身在栈,但它内部 char* 指向的缓冲区一定在堆)。
- 函数内无
static无extern:栈(哪怕是个std::vector<:map std::string>></:map>) - 含
new/malloc表达式:堆(返回指针,指向堆内存) - 文件作用域(函数外)或带
static/extern:数据段 -
const字符串字面量、constexpr变量:通常进.rodata,只读
真正容易被忽略的点:栈上对象的成员如果是指针,它指向的地方可能在堆(如 std::vector 的 data_)、也可能在栈(如 std::array 的内嵌数组)——得一层层看实际内存分配点,不能只看变量名声明位置。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











