本文转载自:https://blog.csdn.net/shulianghan/article/details/20472269

C语言程序内存分配

(1) 内存分区状况

栈区 (stack) : 

-- 分配, 释放方式 : 由编译器自动分配 和 释放;

-- 存放内容 : 局部变量, 参数;

-- 特点 : 具有 后进先出 特性, 适合用于 保存 回复 现场;

堆区 (heap) :

-- 分配, 释放方式 : 由程序员手动 分配(malloc) 和 释放(free), 如果程序员没有释放, 那么程序退出的时候, 会自动释放;

-- 存放内容 : 存放程序运行中 动态分配 内存的数据;

-- 特点 : 大小不固定, 可能会动态的 放大 或 缩小;

堆区内存申请 :

-- 申请过程 : OS中有一个记录空闲内存地址的链表, 如果程序员申请内存, 就会找到空间大于申请内存大小的节点, 将该节点从空间内存链表中删除, 并分配该节点;

-- 剩余内存处理 : 系统会将多余的部分重新放回 空闲内存链表中;

-- 首地址记录大小 : 分配内存的首地址存放该堆的大小, 这样释放内存的时候才能正确执行;

全局区/静态区 (数据段 data segment / bss segment) : 

-- 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;

-- 存放内容 : 全局变量, 静态变量;

-- 特点 : 全局变量 和 静态变量存储在一个区域, 初始化的两种变量 和 未初始化的 存储在不同区域, 但是两个区域是相邻的;

常量区 : 

-- 分配, 释放方式 : 退出程序由系统自动释放;

-- 存放内容 : 常量; (比如char *s = "hello",此处的hello就存储在常量区)

代码区 (text segment) : 

-- 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;

-- 存放内容 : 存放函数体的二进制代码。

内存存放顺序 (由上到下) : 栈区 -> 堆区 -> 全局区 -> 常量区 -> 代码区;

(2) 内存分配方式

全局内存分配 :

-- 生命周期 : 编译时分配内存, 程序退出后释放内存, 与 程序 的生命周期相同;

-- 存储内容 : 全局变量, 静态变量;

栈内存分配 :

-- 生命周期 : 函数执行时分配内存, 执行结束后释放内存;

-- 特点 : 该分配运算由处理器处理, 效率高, 但是栈内存空间有限;

堆内存分配 :

-- 生命周期 : 调用 malloc()开始分配, 调用 free()释放内存, 完全由程序员控制;

-- 谨慎使用 : 如果分配了 没有释放, 会造成内存泄露, 如果频繁 分配 释放 会出现内存碎片;

(3) register变量

使用场景 : 如果 一个变量使用频率特别高, 可以将这个变量放在 CPU 的寄存器中;

-- 修饰限制 : 只有 局部变量 和 参数 可以被声明为 register变量, 全局 和 静态的不可以;

-- 数量限制 : CPU 寄存器 很宝贵, 不能定义太多register变量;

(4) extern 变量

extern变量概念 : 声明外部变量, 外部变量就是在函数的外部定义的变量, 在本函数中使用;

-- 作用域 : 从外部变量定义的位置开始, 知道本源码结束都可以使用, 但是只能在定义extern后面使用, 前面的代码不能使用;

-- 存放位置 : 外部变量 存放在 全局区;

extern变量作用 : 使用extern修饰外部变量, ① 扩展外部变量在本文件中的作用域, ② 将外部变量作用域从一个文件中扩展到工程中的其它文件;

extern声明外部变量的情况 :

-- 单个文件内声明 : 如果不定义在文件开头, 其作用范围只能是 定义位置开始, 文件结束位置结束;

-- 多个文件中声明 : 两个文件中用到一个外部变量, 只能定义一次, 编译 和 连接的时候, 如果没有这个外部变量, 系统会知道这个外部变量在别处定义, 将另一个文件中的外部变量扩展到本文件中;

extern编译原则 :

-- 本文件中能找到 : 编译器遇到 extern 的时候, 现在本文件中找外部变量的定义的位置, 如果找到, 就将作用域扩展到 定义的位置 知道文件结束;

-- 本文件中找不到 : 如果本文件中找不到, 连接其它文件找外部变量定义, 如果找到, 将外部变量作用域扩展到本文件中;

-- 外部文件找不到 : 报错;

使用效果 : extern 使用的时候, 可以不带数据类型;

-- 本文件 : int A = 0; 在第10行, extern A 在第一行, 那么A的作用域就扩展为从第一行到文件末尾;

-- 多文件 : 在任意文件中定义了 int A = 0; 在本文件中声明 extern A, 那么从当前位置到文件末尾都可以使用该变量;

(5) static变量 与 全局变量区别

static 变量 与 全局变量 相同点 : 全局变量是静态存储的, 存储的方式 和 位置基本相同;

static 变量 与 全局变量的不同点 : 全局变量的作用域是 整个项目工程 横跨过个文件, 静态变量的作用域是 当前文件, 其它文件中使用是无效的;

变量存储位置 : 全局变量 和 静态变量 存放在 全局区/静态区, 局部变量存放在 栈区(普通变量) 和 堆区(指针变量);

变量静态化 :

-- 局部变量 : 局部变量 加上 static , 相当于将局部变量的生命周期扩大到了整个文件, 作用域不改变;

-- 全局变量 : 全局变量 加上 static , 相当于将全局变量的作用域缩小到了单个文件, 生命周期是整个程序的周期;

关于函数头文件的引申 :

-- 内部函数 : 单个文件中使用的内部函数, 仅在那个特定文件中定义函数即可;

-- 全局函数 : 如果要在整个工程中使用一个全局函数, 需要将这个函数定义在一个头文件中;

static变量与普通变量区别 :

-- static全局变量 与 全局变量区别 : static 全局变量 只初始化一次, 防止在其它文件中使用;

-- static局部变量 与 局部变量区别 : static 局部变量 只初始化一次, 下一次依据上一次结果;

static函数与普通函数区别 : static 函数在内存中只保留一份, 普通函数 每调用一次, 就创建一个副本;

(6) 堆 和 栈比较

堆(heap)和栈(stack)区别 :

-- 申请方式 : stack 由系统自动分配, heap 由程序员进行分配;

-- 申请响应 : 如果 stack 没有足够的剩余空间, 就会溢出; 堆内存从链表中找空闲内存;

-- 内存限制 : stack 内存是连续的, 从高位向低位扩展, 而且很小, 只有几M, 是事先定好的, 在文件中配置; heap 是不连续的, 从低位向高位扩展, 系统是由链表控制空闲程序, 链表从低地址到高地址, 堆大小受虚拟内存限制, 一般32位机器有4G heap;

-- 申请效率 : stack 由系统分配, 效率高; heap 由程序员分配, 速度慢, 容易产生碎片;

(7) 各区分布情况

由上到下顺序 : 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区;

验证分区状况 : 

-- 示例程序 : 

 /*************************************************************************
> File Name: memory.c
> Author: octopus
> Mail: octopus_work.163.com
> Created Time: Mon 10 Mar 2014 08:34:12 PM CST
************************************************************************/ #include<stdio.h>
#include<stdlib.h> int global1 = , global2 = , global3 = ; void function(void)
{
int local4 = , local5 = , local6 = ;
static int static4 = , static5 = , static6 = ;
int *p2 = (int*)malloc(sizeof(int)); printf("子函数 局部变量 : \n");
printf("local4 : %p \n", &local4);
printf("local5 : %p \n", &local5);
printf("local6 : %p \n", &local6); printf("子函数 指针变量 : \n");
printf("p2 : %p \n", p2); printf("全局变量 : \n");
printf("global1 : %p \n", &global1);
printf("global2 : %p \n", &global2);
printf("global3 : %p \n", &global3); printf("子函数 静态变量 : \n");
printf("static4 : %p \n", &static4);
printf("static5 : %p \n", &static5);
printf("static6 : %p \n", &static6); printf("子函数地址 : \n");
printf("function : %p \n", function);
} int main(int argc, char **argv)
{
int local1 = , local2 = , local3 = ;
static int static1 = , static2 = , static3 = ;
int *p1 = (int*)malloc(sizeof(int));
const int const1 = ;
char *char_p = "char"; printf("主函数 局部变量 : \n");
printf("local1 : %p \n", &local1);
printf("local2 : %p \n", &local2);
printf("local3 : %p \n", &local3);
printf("const1 : %p \n", &const1); printf("主函数 指针变量 : \n");
printf("p1 : %p \n", p1); printf("全局变量 : \n");
printf("global1 : %p \n", &global1);
printf("global2 : %p \n", &global2);
printf("global3 : %p \n", &global3); printf("主函数 静态变量 : \n");
printf("static1 : %p \n", &static1);
printf("static2 : %p \n", &static2);
printf("static3 : %p \n", &static3); printf("字符串常量 : \n");
printf("char_p : %p \n", char_p); printf("主函数地址 : \n");
printf("main : %p \n", main); printf("= = = = = = = = = = = = = = = \n"); function(); return ;
}

-- 执行结果 : 

 [root@ip28 pointer]# gcc memory.c
[root@ip28 pointer]# ./a.out
主函数 局部变量 :
local1 : 0x7fff75f5eedc
local2 : 0x7fff75f5eed8
local3 : 0x7fff75f5eed4
const1 : 0x7fff75f5eed0
主函数 指针变量 :
p1 : 0x19bad010
全局变量 :
global1 : 0x600e14
global2 : 0x600e18
global3 : 0x600e1c
主函数 静态变量 :
static1 : 0x600e34
static2 : 0x600e30
static3 : 0x600e2c
字符串常量 :
char_p : 0x4009f7
主函数地址 :
main : 0x40065f
= = = = = = = = = = = = = = =
子函数 局部变量 :
local4 : 0x7fff75f5eea4
local5 : 0x7fff75f5eea0
local6 : 0x7fff75f5ee9c
子函数 指针变量 :
p2 : 0x19bad030
全局变量 :
global1 : 0x600e14
global2 : 0x600e18
global3 : 0x600e1c
子函数 静态变量 :
static4 : 0x600e28
static5 : 0x600e24
static6 : 0x600e20
子函数地址 :
function : 0x400528

C语言程序内存的分区的更多相关文章

  1. C语言程序内存布局

    C语言程序内存布局 如有转载,请注明出处:http://blog.csdn.net/embedded_sky/article/details/44457453 作者:super_bert@csdn 一 ...

  2. C语言程序内存分布

     一个进程的数据在内存中的布局如下图: bss段(bss segment):可读可写不可执行,通常用来存放程序中未初始化的全局变量.bss是英文Block Started by Symbol的简称.b ...

  3. (十一)C语言中内存堆和栈的区别

    在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到.但对于很多的初学着来说,堆栈是一个很模糊的概念. 堆栈:一种数据结构.一个在程序运行时用于存放的地方,这可能是很多初学者的认 ...

  4. C语言程序猿必会的内存四区及经典面试题解析

    前言: 为啥叫C语言程序猿必会呢?因为特别重要,学习C语言不知道内存分区,对很多问题你很难解释,如经典的:传值传地址,前者不能改变实参,后者可以,知道为什么?还有经典面试题如下: #include & ...

  5. 一起talk C栗子吧(第一百三十一回:C语言实例--C程序内存布局三)

    各位看官们,大家好.上一回中咱们说的是C程序内存布局的样例,这一回咱们继续说该样例.闲话休提,言归正转.让我们一起talk C栗子吧. 看官们,关于C程序内存布局的样例,我们在前面的两个章回都介绍过了 ...

  6. C语言程序的内存布局

    C语言程序的内存布局 一:C语言程序的存储区域 C语言编写的程序经过编绎-链接后,将形成一个统一的文件,它由几个部分组成,在程序运行时又会产生几个其他部分,各个部分代表了不同的存储区域: 1.代码段( ...

  7. C语言程序读写文件(文件内存一个十进制数,每读一次数值加一)

    1.问题:C语言程序实现读写一个txt文件,txt文件中存储一个十进制数.每读一次该数值加一. 2.实现:新建一个文件夹,在该文件夹中建一个outputFileName.txt文件.内容是:1,再在该 ...

  8. c语言之内存管理

    在计算机系统,特别是嵌入式系统中,内存资源是非常有限的.尤其对于移动端开发者来说,硬件资源的限制使得其在程序设计中首要考虑的问题就是如何有效地管理内存资源.本文是作者在学习C语言内存管理的过程中做的一 ...

  9. C/C++程序内存的各种变量存储区域和各个区域详解

    转自 https://blog.csdn.net/jirryzhang/article/details/79518408 C语言在内存中一共分为如下几个区域,分别是: 1. 内存栈区: 存放局部变量名 ...

随机推荐

  1. POJ 1200 Crazy Search (哈希)

    题目链接 Description Many people like to solve hard puzzles some of which may lead them to madness. One ...

  2. BSGS算法及其扩展

    bsgs算法: 我们在逆元里曾经讲到过如何用殴几里得求一个同余方程的整数解.而\(bsgs\)就是用来求一个指数同余方程的最小整数解的:也就是对于\(a^x\equiv b \mod p\) 我们可以 ...

  3. Python人工智能之路 - 第四篇 : jieba gensim 最好别分家之最简单的相似度实现

    简单的问答已经实现了,那么问题也跟着出现了,我不能确定问题一定是"你叫什么名字",也有可能是"你是谁","你叫啥"之类的,这就引出了人工智能 ...

  4. 【文件】使用word的xml模板生成.doc文件

    一.编辑模板 替换地方以变量标记如“案件编号”可写成{caseNo} template.xml 二.准备数据 以HashMap封装数据,原理是替换模板中的变量 三.替换操作 选择输出位置:writeP ...

  5. Android的网络通信机制

    1. Socket接口 不常用 2.HttpURLConnection接口 3. HttpClient接口 http://blog.csdn.net/ccc20134/article/details/ ...

  6. 基于URL的权限管理(三)

    思路:先创建一个专门的类ActiveUser用于存储用户登录的信息,主要用于存储用户id,账户,名称,菜单,权限. 认证拦截器主要是查看用户是否已登陆,如果没有转发到登陆界面,用户用账户跟密码登录时候 ...

  7. 【CTF MISC】隐写术wireshark找出图片-“强网杯”网络安全挑战赛writeup

    这场CTF中有一道题是分析pcap包的.. 13.大黑阔: 从给的pcap包里把图片提取出来,是一张中国地图. 题目提示是黑阔在聊天,从数据里可以找出几段话. 思路:主要考察wireshark的过滤规 ...

  8. Libevent源码分析—event_base_dispatch()

    我们知道libevent是一个Reactor模式的事件驱动的网络库.   到目前为止,我们已经看了核心的event和event_base结构体的源码,看了初始化这两个结构体的源码,看了注册event的 ...

  9. mysql主从配置 转自http://www.cnblogs.com/sustudy/p/4174189.html

    1.确保主数据库与从数据库一模一样. 例如:主数据库里的a的数据库里有b,c,d表,那从数据库里的就应该有一个模子刻出来的a的数据库和b,c,d表 2.在主数据库上创建同步账号. GRANT REPL ...

  10. 网站遭遇CC及DDOS攻击紧急处理方案

    检测访问是否是CC攻击的命令: 80口为网站的访问端口,可以根据实际情况进行修改 # netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: ' ...