C语言之程序中内存的来源:栈 堆 数据段

简介:

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


一:栈(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

相关文章
|
2月前
|
存储 IDE Java
java设置栈内存大小
在Java应用中合理设置栈内存大小是确保程序稳定性和性能的重要措施。通过JVM参数 `-Xss`,可以灵活调整栈内存大小,以适应不同的应用场景。本文介绍了设置栈内存大小的方法、应用场景和注意事项,希望能帮助开发者更好地管理Java应用的内存资源。
97 4
|
4月前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
120 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
4月前
|
算法 Java
堆内存分配策略解密
本文深入探讨了Java虚拟机中堆内存的分配策略,包括新生代(Eden区和Survivor区)与老年代的分配机制。新生代对象优先分配在Eden区,当空间不足时执行Minor GC并将存活对象移至Survivor区;老年代则用于存放长期存活或大对象,避免频繁内存拷贝。通过动态对象年龄判定优化晋升策略,并介绍Full GC触发条件。理解这些策略有助于提高程序性能和稳定性。
|
4月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
134 5
|
5月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
130 6
|
5月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
132 5
|
5月前
|
C语言
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性。本文探讨了C语言中的错误类型(如语法错误、运行时错误)、基本处理方法(如返回值、全局变量、自定义异常处理)、常见策略(如检查返回值、设置标志位、记录错误信息)及错误处理函数(如perror、strerror)。强调了不忽略错误、保持处理一致性及避免过度处理的重要性,并通过文件操作和网络编程实例展示了错误处理的应用。
148 4
|
5月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
127 1
|
1月前
|
存储 缓存 算法
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
174 29
JVM简介—1.Java内存区域
|
1月前
|
消息中间件 Java 应用服务中间件
JVM实战—2.JVM内存设置与对象分配流转
本文详细介绍了JVM内存管理的相关知识,包括:JVM内存划分原理、对象分配与流转、线上系统JVM内存设置、JVM参数优化、问题汇总。
JVM实战—2.JVM内存设置与对象分配流转

热门文章

最新文章

下一篇
oss创建bucket