C语言内存分布

典型的C语言程序内存表示分区共有5个部分:

  1. 正文段 Text segment
  2. 已初始化数据段(数据段)Initialized data segment
  3. 未初始化数据段(bss)Uninitialized data segment
  4. 堆 Stack
  5. 栈 Heap

具体分布图

各个分区的作用

  • 正文段

    • CPU执行的机器指令部分
    • 通常可共享
    • 常常是只读的
  • 已初始化数据段(数据段)
    • 包含程序中需明确赋初始值的变量
    • 保存已经初始化的全局变量
  • 未初始化数据段(BSS)
    • 在程序开始执行之前,内核将此段中的数据初始化为0或空指针
    • 保存未初始化的全局变量(注意:即使是赋值为0也是未初始化!
    • 存储自动变量(如函数形参)及每次函数调用所需保存的信息
    • 每次函数调用时,存放其返回地址及调用者的环境信息(如某些机器寄存器的值)
    • 为最近被调用的函数分配自动变量和临时变量的存储空间
    • 动态存储分配

初始化?

上面提到,对全局变量来说,如果是赋值为0仍是未初始化。下面给出实际实验结果:

示例代码1


#include <stdio.h> int a; int main(int argc, char const *argv[])
{
printf("hello\n");
return 0;
}

编译后查看内存分布:

示例代码2


#include <stdio.h> int a = 0; int main(int argc, char const *argv[])
{
printf("hello\n");
return 0;
}

编译后查看内存分布:

可以看到,各个存储区域数值没有变化。

示例代码3


#include <stdio.h> int a = 1; int main(int argc, char const *argv[])
{
printf("hello\n");
return 0;
}

编译后查看内存分布:

可以看到,对全局变量进行真正的初始化之后,bss少了4个字节,data段多出了4个字节。

关于static的问题

示例代码4

先看看相对上一例子,多了一个局部变量之后的内存分布。


#include <stdio.h> int a = 1; int main(int argc, char const *argv[])
{
int b;
printf("hello\n");
return 0;
}

编译后查看内存分布:

可以看到,内存分布是没有变化的,局部变量b会在栈上分配到内存。

示例代码5

如果把b定义成static呢?


#include <stdio.h> int a = 1; int main(int argc, char const *argv[])
{
static int b;
printf("hello\n");
return 0;
}

编译后查看内存分布:

可以看到,此时bss上多出了8个字节。

示例代码6

如果给b赋初始值0呢?


#include <stdio.h> int a = 1; int main(int argc, char const *argv[])
{
static int b = 0;
printf("hello\n");
return 0;
}

编译后查看内存分布:

可以看到,跟上一个例子相比没有变化,说明跟全局变量一样,static变量赋值为0仍是未初始化。

示例代码7

如果给b赋初始值1呢?


#include <stdio.h> int a = 1; int main(int argc, char const *argv[])
{
static int b = 1;
printf("hello\n");
return 0;
}

编译后查看内存分布:

可以看到,bss少了4个字节,而data多了4个字节,说明静态变量和全局变量同理,初始化之后是存在data段中的。

关于static的用处

示例代码8


#include <stdio.h> int x = 4; void incre() {
static int x = 1;
x *= x + 1;
printf("%d\n", x);
} int main(int argc, char const *argv[])
{
int i;
for (i = 1; i < x; i++) {
incre();
}
return 0;
}

运行结果为:

可以看到,函数increx的作用域存在于其局部,但是却在每次调用函数的时候沿用之前的值!这是因为static定义的变量是静态变量,有着静态存储位置(变量存储位置固定不动,若在代码中已经初始化则存在于data段,否则存在于bss段),而不是存在于栈上,因此每次调用函数读取到的变量的值都是静态存储区的值。

static的意义

  1. 全局静态变量

    • 不会被其它文件所访问和修改
    • 其它文件中可以使用相同名字的变量,不会发生冲突
  2. 局部静态变量

    • 可以用作计数器,每次函数调用的时候可以进行计数
  3. 静态函数

    • 其它文件中可以定义相同名字的函数,不会发生冲突
    • 静态函数不能被其它文件所用
    • 静态函数会被分配在一个一直使用的存储器,直到程序退出,避免了调用函数时进栈出栈,提升运行速度

参考书目

  1. 《Unix环境高级编程》(中文第三版)
  2. 《C primer plus》(中文第五版)

参考博客

C语言存储空间布局以及static详解——奔人之旅

C语言内存分布的更多相关文章

  1. C语言内存分布之数据段

    不管我们以后是自己写代码还是读别人的代码,都应该想想这个变量默认存储的位置.在我们以后的嵌入式开发中,技巧性的代码越来越多的时候,我们可能把某一些代码放在一段.我们可以通过修改变量或者代码默认放置的段 ...

  2. 程序的内存分布 - 以 Linux 为例,基于 C 语言分析

    这里以 Linux 为例,用 C 语言进行演示. 内存模型 - 内存空间名称 内容 读写操作 分配时机 高地址 kernel 内核空间 命令行参数.环境变量等 不可读写 程序运行时 - stack 栈 ...

  3. 深入理解C语言内存管理

    之前在学Java的时候对于Java虚拟机中的内存分布有一定的了解,但是最近在看一些C,发现居然自己对于C语言的内存分配了解的太少. 问题不能拖,我这就来学习一下吧,争取一次搞定. 在任何程序设计环境及 ...

  4. 内存模型 Memory model 内存分布及程序运行中(BSS段、数据段、代码段、堆栈

    C语言中内存分布及程序运行中(BSS段.数据段.代码段.堆栈) - 秦宝艳的个人页面 - 开源中国 https://my.oschina.net/pollybl1255/blog/140323 Mem ...

  5. 深入理解Linux C语言内存管理

    问题不能拖,我这就来学习一下吧,争取一次搞定. 在任何程序设计环境及语言中,内存管理都十分重要. 内存管理的基本概念 分析C语言内存的分布先从Linux下可执行的C程序入手.现在有一个简单的C源程序h ...

  6. C++类内存分布

    http://www.cnblogs.com/jerry19880126/p/3616999.html#undefined 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看 ...

  7. C语言内存对齐详解

    一.字节对齐基本概念 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型 ...

  8. C语言内存对齐详解(2)

    接上一篇:C语言内存对齐详解(1) VC对结构的存储的特殊处理确实提高CPU存储变量的速度,但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式.VC 中提供了#pr ...

  9. C语言内存对齐详解(3)

    接上一篇:C语言内存对齐详解(2) 在minix的stdarg.h文件中,定义了如下一个宏: /* Amount of space required in an argument list for a ...

随机推荐

  1. 第二个Sprint冲刺第 七天(燃尽图)

  2. [软工课程博客] 求解第N个素数

    任务 求解第 10,0000.100,0000.1000,0000 ... 个素数(要求精确解). 想法 Sieve of Eratosthenes 学习初等数论的时候曾经学过埃拉托斯特尼筛法(Sie ...

  3. VC2013一些感受

    这是一个我很早就在用的编译器,因为是微软官方的,极其高大上,安装包,界面错误的提示处理都相当简洁明了,不像VC6.0以及Codeblock太low了 但其实,我想说,我并不怎么用这玩意~就像Siri做 ...

  4. 读C#程序最小公倍数答案就是:2123581660200

    阅读下面程序,请回答如下问题: 问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间 ...

  5. maven测试时中文乱码问题解决方法

    pom.xml增加-Dfile.encoding=UTF-8配置,如下: <plugin> <!--升级到新版本解决控制台乱码问题--> <groupId>org. ...

  6. 【版本管理】自定义git

    Git除了可配置user.name和user.email外,实际上,Git还有很多可配置项. 如 $ git config --global color.ui true,让Git显⽰示颜⾊色,会让命令 ...

  7. 一本通1649【例 2】2^k 进制数

    1649:[例 2]2^k 进制数 时间限制: 1000 ms         内存限制: 524288 KB [题目描述] 原题来自:NOIP 2006 提高组 设 r 是个 2k 进制数,并满足以 ...

  8. suse11/12关闭防火墙

    suse11关闭操作为:service SuSEfirewall2_setup stopservice SuSEfirewall2_init  stop 取消开机启动防火墙:chkconfig SuS ...

  9. 【洛谷P4955 】[USACO14JAN]越野滑雪越野滑雪

    题目链接:ヾ(≧∇≦*)ゝ 对于每一个点可以向它右边的点和下面的点连边,权值就为两个点的高度差 然后再把所有的边按边权从小到大排序,并查集加点 最后判断当前集合是否涵盖所有的航点,如果是,就输出最后一 ...

  10. 为什么使用消息队列,为什么使用RabbitMQ、springAMQP

    1.为什么使用消息队列? 2.为什么使用RabbbitMQ? 3.为什么使用spring AMQP?