-
在c语言中内存包括 堆内存、栈内存、全局常态区、常量区



-
变量分为:
按存储类别分为自动变量、静态变量、寄存器变量(不在主存中,而在 CPU 寄存器里)、外部变量
按作用域分类:局部变量、全局变量、形参
按生命周期分类:自动存储期、静态存储期、动态存储期
按数据类型分类:基本类型、派生类型、空类型
-
存储类别


4.1. 自动变量(Automatic)
c
void func() {
int x = 10; // 等价于 auto int x = 10; 存放在栈上
char c; // 未初始化 → 垃圾值!
}
auto(通常省略),存储在栈(stack),函数调用时分配,函数返回时自动释放,不会自动初始化 → 值为垃圾数据
4.2. 静态变量(Static)
c
// 全局静态(仅本文件可见)
static int global_count = 0; // → .data 段
void counter() {
static int local_count = 0; // 只初始化一次,函数退出不销毁 → .bss 段(值为 0)
local_count++;
static char msg[] = "Hi"; // → .data 段(含字符串)
printf("%d\n", local_count);
}
.bss(Block Started by Symbol)段不占可执行文件空间,运行时由 OS 清零。
全局静态变量(文件作用域 + static)
局部静态变量(函数内 + static)
如果显式初始化(如 = 5)→ 已初始化数据段(.data)
如果未初始化或初始化为 0 → 未初始化数据段(.bss)
存储在数据段(.data 或 .bss)
程序启动时分配,结束时释放
自动初始化为 0(即使你没写)
生命周期贯穿整个程序
4.3. 外部变量(External)
c
// file1.c
int global_var = 42; // 定义(分配内存)// 定义 → .data 段
// file2.c
extern int global_var; // 声明(不分配内存,引用 file1.c 的变量)
外部变量和普通全局变量内存位置相同,extern 只是"告诉编译器这个变量在别处定义"。
本质:就是全局变量,只是用 extern 在其他文件中声明
内存位置:
显式初始化 → .data 段
未初始化 → .bss 段
4.4. 寄存器变量(Register)
c
register int i; // 建议编译器将 i 放入 CPU 寄存器(加速访问)
⚠️ 现代编译器优化能力强,通常忽略 register,且不能取地址(&i 非法)
编译器可能忽略该请求(现代优化器自行决定)
不能取地址(&x 非法)→ 因为寄存器没有内存地址
访问速度最快(比栈快得多)
补充:

局部变量 → 用自动变量(栈):高效、安全
需要保持状态 → 用 static:避免全局污染
跨文件共享 → 用 extern + 全局变量:谨慎使用
不要滥用 register:让编译器优化
永远初始化局部变量:避免栈上的垃圾值
- 作用域

全局变量默认具有外部链接性(可被其他文件通过 extern 访问),加 static 可变为内部链接性(仅本文件可见)。
局部变量 栈区(Stack)
全局变量 已初始化的全局变量:存储在 .data 段(初始化数据段)。
未初始化或初始化为零的全局变量:存储在 .bss 段(未初始化数据段,程序启动时自动清零)。
形参(形式参数)栈区(Stack)

- 生命周期


栈溢出:栈区空间有限(通常几MB),递归过深或局部变量过大可能导致栈溢出。
内存泄漏:动态分配的内存未释放会导致泄漏,长期运行的程序可能因此崩溃。
野指针:释放堆内存后未置空指针,再次访问会导致未定义行为。
静态变量的初始化:静态局部变量仅在第一次进入作用域时初始化,后续调用保留值。 - 数据类型

c
int age; // 基本类型
char name[20]; // 数组(派生)
struct Point p; // 结构体(派生)
void *ptr; // void 指针
- 对比

优先使用局部变量(减少全局状态,提高模块化)
全局变量加 static(除非明确需要跨文件共享)
局部变量务必初始化(避免垃圾值)
慎用 register(让编译器优化)
动态内存用 malloc/free(不属于"变量种类",但需手动管理)
c
#include <stdio.h>
static int global_static = 100; // 全局、静态存储期、内部链接
void func() {
auto int local_auto = 200; // 局部、自动存储期(auto 可省略)
static int local_static = 300; // 局部作用域,静态存储期
printf("local_static = %d\n", local_static);
local_static++; // 下次调用会保留值
}
int main() {
func(); // 输出 300
func(); // 输出 301
return 0;
}
栈:主要用于存储局部变量(无论是基本类型还是派生类型),随着函数调用进入和退出而自动分配和回收。
数据段:用于存储全局变量和静态变量,这些变量在程序运行期间一直存在。
堆:用于动态内存分配,适用于那些需要在运行时确定大小的数据结构。
只读数据段:存储常量数据,程序运行过程中不可修改。