C语言程序的内存地址分配

📅 2026/7/21 6:36:38
C语言程序的内存地址分配
当一个C程序被编译为可执行程序我们运行这个可执行程序时系统会为这个程序分配一个虚拟内存以下就是其分配详情不同的操作系统分的内存大小可能不同但是顺序都是一样的只不过每个区域的大小不一高地址 ┌─────────────────────┐ 0xFFFFFFFF│ 内核空间 │ 操作系统占用用户程序无法访问│ 1GB供内核使用 │├─────────────────────┤ 0xC00000003GB 边界│ ││ 栈区 ↓ │ ← 向下增长从高地址向低地址│ 局部变量、形参 │├─────────────────────┤│ ││ 空洞 │ ← 栈和堆之间的大片空闲区域│ 可动态调整 ││ │├─────────────────────┤│ 堆区 ↑ │ ← 向上增长从低地址向高地址│ malloc/calloc 分配│├─────────────────────┤│ .bss段 │ ←未初始化的全局/静态变量默认值为0│ │├─────────────────────┤│ .data段 │ ←已初始化的全局/静态变量有初始值│ │├─────────────────────┤│ .rodata段 │ ←只读数据字符串常量、const 修饰的变量│ │├─────────────────────┤│ .text段 │ ← 代码段程序的机器指令只读│ 程序指令/机器码 ││ │低地址 └─────────────────────┘ 0x08048000Linux 默认加载地址1. 代码段.text只读存放内容程序的机器指令CPU 执行的二进制代码权限只读防止程序意外修改自己的指令生命周期程序启动到结束一直存在举例你写的printf(hello);编译后就在这里// 函数体编译后存放在 .text 段void func() {int a 10; // 函数指令在这里但变量 a 在栈上}2. 只读数据段.rodata常量区存放内容字符串常量、const修饰的全局变量权限只读修改会导致段错误生命周期程序启动到结束一直存在‘char *str hello; // hello 存放在 .rodata 段const int num 100; // num 存放在 .rodata 段全局 const3. 数据段.data已初始化数据段存放内容已经初始化的全局变量、静态变量初始值不为 0权限可读写生命周期程序启动到结束一直存在int global 100; // 存放在 .data 段static int count 5; // 存放在 .data 段4. BSS 段.bss未初始化数据段存放内容未初始化的全局变量、静态变量默认值为 0权限可读写生命周期程序启动到结束一直存在特性程序加载时操作系统会把 BSS 段全部清零int global2; // 存放在 .bss 段默认值为 0static int count2; // 存放在 .bss 段默认值为 05. 堆区Heap动态分配存放内容malloc、calloc、realloc分配的内存特点手动分配和释放mallocfree从低地址向高地址增长sbrk/mmap空间较大但分配速度比栈慢如果不释放会造成内存泄漏int *p malloc(100 * sizeof(int)); // 在堆上分配 400 字节// ... 使用 ...free(p); // 手动释放6. 栈区Stack函数调用存放内容局部变量、形参、函数返回值、函数调用信息栈帧特点自动分配和释放函数调用时压栈返回时弹栈从高地址向低地址增长向下增长空间有限通常默认 8MB超出会栈溢出分配速度极快移动栈指针即可void func(int a, int b) { // a 和 b 在栈上int x 10; // x 在栈上char str[100]; // str 在栈上} // 函数返回后x、str、a、b 全部被自动回收