博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C语言之程序中内存的来源:栈 堆 数据段
阅读量:7187 次
发布时间:2019-06-29

本文共 2929 字,大约阅读时间需要 9 分钟。

程序在运行的时候,其内存的来源主要通过三种方法:  栈  堆  数据段,总体上来讲栈是一般用来存放小内存的局部变量,堆内存和数据段的属性很像,在使用的的时候,如果这个变量是伴随程序一直存在则使用全局变量,也就是放在数据段,如果一个变量使用完了就没用了,那么就适合用堆内存(先申请,然后释放即可),


一:栈(stack):

1:栈在使用的时候是编译器自动分配内存空间的,不需要程序员的干涉,其次栈的大小是有限的,所以当我们定义的变量需要大片的内存的时候就不适合使用栈,

2:栈存放的是普通变量,栈的在使用的时候是反复使用的,所以栈内存是脏的,在定义普通变量的时候,如果不对变量进行初始化,那么变量的值就是随机的。

3:栈是先进后出的,其内存空间是向下增长的。


二:堆(heap):

1:堆得使用时是由程序员来操作的,程序员通过malloc来向内存申请堆内存,使用完以后通过free来释放这部分内存,如果这部分内存在使用完以后没有进行内存的释放,那么这部分内存管理器就会认为这部分内存一直被占用的,体现出来的就是程序吃内存,也就是所谓的内存泄漏,如果没有释放内存,则被占用的内存只有当程序结束以后才会被释放。一般需要大片的内存时才使用堆,堆是先进先出的,其内存空间是向上增长的。

代码示例:

1
<span style=
"font-family:'宋体', SimSun;font-size:20px;"
>#include <stdio.h><br data-filtered=
"filtered"
>#include <stdlib.h><br data-filtered=
"filtered"
>
int 
main(
void
)<br data-filtered=
"filtered"
>{<br data-filtered=
"filtered"
>
//申请内存<br data-filtered="filtered">int *p = (int *)malloc(100);<br data-filtered="filtered">if(p == NULL)  //错误检查<br data-filtered="filtered">{<br data-filtered="filtered">printf("error \n");<br data-filtered="filtered">return -1;<br data-filtered="filtered">}<br data-filtered="filtered">//内存使用S<br data-filtered="filtered">*(p+4) = 1024;<br data-filtered="filtered">*(p+3000) = 111;<br data-filtered="filtered">printf("*(p+3) = %d\n", *(p+4));<br data-filtered="filtered">printf("*(p+30000)) = %d\n", *(p+3000));<br data-filtered="filtered">printf("p = %p \n",p);<br data-filtered="filtered">printf("(p +4) = %p \n",(p +4));<br data-filtered="filtered"><br data-filtered="filtered">free(p);   //释放内存<br data-filtered="filtered"><br data-filtered="filtered">printf("*(p+3) = %d\n", *(p+4));<br data-filtered="filtered">printf("*(p+30000)) = %d\n", *(p+3000));<br data-filtered="filtered">printf("p = %p \n",p);<br data-filtered="filtered">printf("(p +4) = %p \n",(p +4));<br data-filtered="filtered"><br data-filtered="filtered">p = NULL;  //避免野指针<br data-filtered="filtered"><br data-filtered="filtered">return 0;<br data-filtered="filtered">}</span>

运行结果:

*(p+3) = 1024

*(p+30000)) = 111

p = 0x8efb008

(p +4) = 0x8efb018

*(p+3) = 1024

*(p+30000)) = 111

p = 0x8efb008

(p +4) = 0x8efb018

分析:

1:堆内存可以越界访问,但是实际中最好还是不要,因为你在使用的时候越界访问就意味着踩到别人了

2:堆内存在释放之后还可以访问,并且访问的值还是不变的,说明堆内存也是脏的,堆内存释放的时候并没有对使用过的没存进行清理。

三:数据段(.data )

1:一个程序主要有数据段(.data) 代码段  和bss段,不同的段具有不同的段属性

数据段:(又叫数据区、静态数据区、静态区)数据段存放的是程序的中显示初始化的全局变量(不包括初始化为0的全局变量),同时需要注意的是全局变量才算是程序的数据,局部变量不是程序变量,只是函数数据

代码段:代码段就是程序中的可执行部分,直观理解代码段就是函数堆叠组成的。代码段是只读的。

bss段:(又叫zero initial 段)bss段存放的是为显示初始化的全局变量已经初始化为0的全局变量(C语言中默认全局变量的初始化就是为0),所以可以理解为bss段就是初始化为0的数据段。

2:放在.data段的变量有两种:第一种是显式初始化为非0的全局变量,另一种是静态局部变量,也就是static修饰的局部变量(普通变量是分配在栈上面,静态局部变量是分布在.data段)



四:代码段中的特殊数据

1:C语言使用char *p = "linux";定义字符串的时候,字符串"linux"实际上是被分配到了代码段上面,换句话说这里的字符串"linux"实际上是一个常量字符串而不是变量字符串。

2:const修饰的类型常量,const的实现方法主要有两种,一种是编译的时候将const修饰的变量放在代码段去实现不可修改(因为代码段是只读的),另一种是由编译器来检查来确保const修饰的常量,但是这种实际上和普通常量样,也是被放在了数据段,所以如果绕过编译器就可以实现修改,具体实现方法是用指针去指向这个常量的内存空间,然后解引用去修改这个常量,gcc中就是这样实现的。



本文转自 菜鸟养成记 51CTO博客,原文链接:http://blog.51cto.com/11674570/1861671

转载地址:http://kmykm.baihongyu.com/

你可能感兴趣的文章
bootstrap Modal的简单笔记
查看>>
统计一串字符串中连续相同元素的个数
查看>>
奋斗例子——>从1.5k到18k, 一个程序员的5年成长之路
查看>>
python2.x之list和tunple及dict
查看>>
后缀表达式太有才了
查看>>
Atom Plugins
查看>>
1.8 字典 1.9 字典练习 2.0/2.1 流程控制-if条件判断
查看>>
软件包安装
查看>>
CentOS6下配置Tomcat7以非root用户在80端口自启动(JSVC)
查看>>
elasticsearch5.0.0中聚合和脚本的变化
查看>>
修改 Docker 中 MySQL 容器的编码
查看>>
HeadFirst设计模式篇七:模板方法模式
查看>>
给自己的区块链添加POW-工作量证明
查看>>
unix ‘’ “” 等笔记
查看>>
子域名间 的session共享
查看>>
webpack使用的一些看法
查看>>
大数据学习系列----文章汇总
查看>>
ios开发:使用sqlite存储数据
查看>>
C++ map下标访问的问题
查看>>
go filepath Abs
查看>>