1. 引言写 C 程序时很多莫名其妙的问题——段错误、野指针、函数返回局部数组出错——追根溯源往往是对内存分区理解不清。2. 五大内存分区C 程序的内存通常分成五块栈区、堆区、全局/静态区、常量区、代码段。栈编译器自动管放局部变量函数一返回就没了堆自己malloc、自己free想用多久用多久全局/静态区放全局变量和static变量程序从头活到尾常量区放字符串字面量和全局const只读改了会崩代码段放编译后的机器指令只读可执行。分区存放内容分配方式生命周期读写权限栈区局部变量、函数参数、返回地址编译器自动函数调用期间可读写堆区malloc申请的内存程序员手动malloc到free可读写数据段已初始化全局/静态变量程序启动时整个进程可读写BSS 段未初始化全局/静态变量程序启动时清零整个进程可读写常量区字符串字面量、const常量编译期确定整个进程只读代码段机器指令编译期确定整个进程只读可执行3. 用代码验证分区可以打印各类变量的地址直观感受分区差异#includestdio.h#includestdlib.hintg_init1;/* 数据段 */intg_uninit;/* BSS 段 */constintg_const2;/* 常量区 */intmain(void){intlocal0;/* 栈 */int*heapmalloc(4);/* 堆 */staticints_local3;/* 数据段 */char*strliteral;/* 指针在栈literal 在常量区 */printf(代码段(函数地址): %p\n,(void*)main);printf(常量区(字符串): %p\n,(void*)str);printf(常量区(const): %p\n,(void*)g_const);printf(数据段(已初始化): %p\n,(void*)g_init);printf(数据段(静态局部): %p\n,(void*)s_local);printf(BSS 段(未初始化): %p\n,(void*)g_uninit);printf(堆区: %p\n,(void*)heap);printf(栈区: %p\n,(void*)local);free(heap);return0;}4. 常见误区误区一局部数组可以返回。局部数组在栈上函数返回后栈帧回收返回的是悬空地址。需要返回时用malloc或传入调用方缓冲区。误区二static局部变量在栈上。它在静态区函数返回后依然存在只是作用域仍限于该函数。误区三const变量一定在常量区。只有全局const和字面量才在只读段函数内的const局部变量通常仍在栈上只是编译器禁止你修改。误区四malloc的内存会自动回收。C 语言没有 GC必须手动free否则进程运行期间一直占用。误区五栈和堆会撞车。在虚拟地址空间里栈向下、堆向上增长中间有较大空隙现代系统上一般不会真的相撞但栈溢出和堆耗尽仍是真实风险。5. 总结C 程序内存分为栈区、堆区、全局/静态区数据段 BSS 段、常量区、代码段五大部分栈由编译器自动管理快但空间小局部变量随函数返回失效堆由程序员手动管理灵活但需自己free注意泄漏与悬空指针全局/静态区贯穿整个进程未初始化变量自动清零常量区只读字符串字面量不可修改代码段存放指令只读可执行。理解内存分区的价值不在于背概念而在于遇到问题时能快速定位这个变量在哪、谁分配、活多久、能不能改。想清楚这四点大部分内存相关的 bug 都能提前避开。
阅读完成 · 觉得有帮助?