C语言 | 栈区空间初探
栈的定义
栈(stack)又名堆栈,堆栈是一个特定的存储区或寄存器,它的一端是固定的,另一端是浮动的 。对这个存储区存入的数据,是一种特殊的数据结构。所有的数据存入或取出,只能在浮动的一端(称栈顶)进行,严格按照“先进后出”的原则存取,位于其中间的元素,必须在其栈上部(后进栈者)诸元素逐个移出后才能取出。在内存储器(随机存储器)中开辟一个区域作为堆栈,叫软件堆栈;用寄存器构成的堆栈,叫硬件堆栈。
- 栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
- 堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS(操作系统)回收,分配方式倒是类似于链表。
本文目录:
- 栈区在虚拟地址空间分布
- 字符串在栈中的存储方式
- 变量在栈中的存储方式
- 数组在栈中的存储方式
- 关于数组越界访问的小测试
- 栈区空间大小
- 总结及相关知识
栈的特点——先进后出
栈是一种一端受限的线性表,它只接受从同一端插入或删除,并且严格遵守先进后出的准则。什么意思呢,我们这样来理解,栈就是一个倒置的桶,这个桶有一定的空间,我们可以用这个桶来做装很多东西。在C语言中有着形如 int 类型占4个字节的空间,char 类型占1个字节空间等等的不同大小的变量类型。而我们在函数中定义一个变量 int a = 10;
,等于我们把一个名为 a 的占据4个字节空间的物体放入栈这个桶中,那么我们再来定义一个变量 char c = 'x'
,同样也放如栈中。那么我们模拟出栈的布局应是如下所示
我们可以看到,在栈中变量c在变量a的上方。因此,出栈的时候只能先出 c 变量再出 a 变量,而我们知道,a 变量是先于 c 变量入栈的,所以栈的特点为 先进后出 。
好了,关于栈的数据结构部分的讨论暂且先停下,下面我们要讨论的是内存中的栈区,而不是我们所说的数据结构栈。
函数内部的变量在栈区申请
我们说函数、全局变量、静态变量的虚拟地址在编译时就可确定,而在函数中使用的变量在运行时确定,函数形参在函数调用时确定。
那么这句话是什么意思呢?函数的入口地址、全局变量在编译阶段就确定的地址,这是编译链接的知识我们今天先不讨论,今天主要讨论一下栈区以及栈区的使用。
栈区空间分布
我们所说的栈区和平时我们用的数据结构中的栈还是有一些不同的。在内存中栈又叫堆栈,它分布在虚拟地址空间中,仅占一小部分。一个程序运行时拥有一个自己的虚拟地址空间,在32位计算机上为 2^32次方大小(4G)的一块内存空间。在这块空间中所有的地址都是逻辑地址,即虚拟的地址,在程序运行到哪一部分空间时把相应的内存页映射到真实的物理地址上。整个虚拟地址空间分布大致如下图所示
在定义变量之前,我们首先要知道,函数中使用的变量在栈上申请空间,至于原因我们下次在讨论。那么对于栈这种数据结构来说,它是由高地址向低地址生长的一种结构。像我们平时在 main函数或是普通的函数中定义的变量都是由栈区来进行管理的。下面进行几个实例以便于我们更加了解栈区的使用。
字符串在栈中申请空间的方式
编写如下C程序:
int main()
{char str[] = { "hello world" };char str2[10];printf("%s \n",str);printf("%s\n",str2);return 0;
}
在 VS 2019中运行
我们在C源码中,给 str
赋值为“Hello World”,而 str2
没有进行赋值。
这里要说明一点,在函数内部会根据函数所用到的空间大小生成函数的栈帧,而后对其内存空间进行 0xcccc cccc
的初始化赋值。而'cc'
在中文编码下就是“烫”字符。有时候我们会说申请的局部变量(函数的作用域下)没有进行赋值其内容会是随机值。这么说其实也没错,原因很简单,在内存中的某个内存块上,无时无刻不伴随着大量程序的使用,而在程序使用过后就会在该内存块处留下一些数据,这些数据我们无法使用在我们看来就是随机值。而在 VS 编译器中为了防止随机值对程序运行结果造成干扰,就通过用初始化为 0xcccc cccc
的方式进行统一的初始化。而字符串的输出时靠字符串末尾的 \0
结束符来确定的,str2 ,中并没有该字符,因此在输出时一直顺着栈向高地址寻找,直到找到 str 中的 \0
结束符。
变量在栈中申请空间的方式
从上图我们也可以看到字符串在栈中是连续申请的。此外,变量、数组等也是在栈中连续申请的,请看下面的实例:
在Linux 上编写如下代码:
#include <stdio.h>
void main(void)
{//整型变量int a = 10;int b = 10;//字符型变量char c = a;char ch = b;//数组型变量int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };int d = 10;// 输出源码char str[] =" \int a = 10;\n \int b = 10;\n \\n \char c = a;\n \char ch = b;\n \\n \int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };\n \int d = 10;\n";printf("%s\n",str);printf("&a = %x \t &b = %x\n",&a, &b);printf("&c = %x \t &ch = %x\n",&c, &ch);for(int i = 0; i < 10; ++i){printf("&arr[%d] = %x \t arr[%d] = %d\n", i, &arr[i], i, arr[i]);}printf("---&arr[10] &arr[11] &arr[12] &arr[13] &arr[14] &arr[15] \n");printf("---%x %x %x %x %x %x\n", &arr[10], &arr[11], &arr[12], &arr[13], &arr[14], &arr[15]);exit(0);
}
在Linux 上编译运行 gcc -std=c99 -o test test.c
./test
其中 -std=c99 表示使用C99语法规则。
我们把输出结果复制到画图板上进行分析。另外,程序每次运行时,程序执行的起始地址不同,最终每次输出的结果也不同(如画图板上输出结果为重新运行的结果),但是这并我影响我们观察的结果。
分析:
如图所示,在标注出的绿色部分是申请的两个整型变量,根据栈的特性和申请的顺序,变量a在靠近高地址处,变量b在靠近低地址处。a、b都是整型变量,占4字节,所以在内存中因该是 e105a30---e105a33
为b变量占据的内存空间,e105a34---e105a37
为a变量占据的内存地址。
注:在图中仅标注出了起始地址。
对于 char 型字符变量 c 和 ch ,他们都只有一个字节的内存空间,但是由于内存对齐机制,他们两个一共占据了 e105a2c---e105a2f
4个字节。虽然如此,在使用时他们任然只使用一个字节。c 对应内存地址为 e105a2f
,ch 对应内存地址为 e105a2e
。
通过观察我们发现,数组中的 arr[11]、arr[12]、arr[13]的地址与我们定义的 ch 、b、a的首地址相同,这是怎么回事呢?
数组在栈中的排布
数组比较特殊,按照我们的理解,栈从高地址位向低地址为生长。按理来说,arr[0] 作为数组的首元素应该在高地址为最先被申请,而 arr[9] 为数组的末位元素理应在栈的低地址位被申请。然而,根据程序打印出的结果我们画出的栈内存布局显示,数组在栈中是顺着地址增长的方向排布的。
C语言 | 栈区空间初探相关推荐
- python空间数据处理_基于Python语言的空间数据处理
龙源期刊网 http://www.doczj.com/doc/7b0e0476172ded630a1cb662.html 基于Python语言的空间数据处理 作者:何丽娴甘淑陈应跃 来源:<价值 ...
- R语言地理空间分析、可视化及模型预测
随着地理信息系统(GIS)和大尺度研究的发展,空间数据的管理.统计与制图变得越来越重要.R语言在数据分析.挖掘和可视化中发挥着重要的作用,其中在空间分析方面扮演着重要角色,与空间相关的包的数量也达到1 ...
- 2021_01_22_R语言在空间可视化方面的英文书籍推荐
R语言在空间可视化方面的英文书籍推荐 #这是我的第一篇blog! #接触R语言在地理空间可视化的应用方向已有接近2个月! #我整理了几本很好的英文书籍,特别有针对性,针对一些想用R在城市规划设计专业中 ...
- R语言绘制空间热力图
先上图 R语言的REmap包拥有非常强大的空间热力图以及空间迁移图功能,里面内置了国内外诸多城市坐标数据,使用起来方便快捷. 开始 首先安装相关包 install_packages("dev ...
- Go语言并发机制初探
Go 语言相比Java等一个很大的优势就是可以方便地编写并发程序.Go 语言内置了 goroutine 机制,使用goroutine可以快速地开发并发程序, 更好的利用多核处理器资源.这篇文章学习 g ...
- Go语言程序结构分析初探
每一种编程语言都有自己的语法.结构以及自己的风格,这也是每种语言展现各自魅力及众不同的地方.Go也不例外,它简单而优雅,与此同时使用起来也很有趣.在本文中,我们将讨论以下几点: Go程序结构 如何运行 ...
- 只读字符串的c语言命令,C语言只读空间 - C 语言程序设计
我们现在看向内存中的只读数据段和代码段构成的只读空间的概念. 代码段 当程序越来越多,代码段也就越来越大.代码段里面的代码是不可以在运行的时候被修改的,在编译的时候就已经定格了.如果我们试图去写它,就 ...
- c语言操作空间怎么打开_学好C语言,离大神更近一步,C环境的安装
我们先来说说为什么要学习C语言: 首先,就现在的几大系统而言,我们看看使用它的都有多少.Windows系统刚出现的时候就是用的C语言,后来才使用了C++和C#等.Linux的底层也是使用C语言编写的, ...
- 频率统计表用c语言_空间矢量脉宽调制建模与仿真(基于C语言的SIMULINK仿真模型 | 基于SVPWM模块的仿真)...
文末有仿真模型下载方式 1.1 基于C语言的SIMULINK仿真模型 使用C语言在MATLAB/SIMULINK中仿真,需要借助s-function builder模块实现.七段式SVPWM仿真模型如 ...
最新文章
- 蓝桥杯java第八届第三题--承压计算
- 理解tcp关闭连接中的time_wait状态
- ArcGIS中合并(merge)、联合(union)、追加(append)、融合(dissolve)的用法区别与联系
- 修改Linux内核的启动Logo和禁用启动光标
- julia在mac环境变量_在Julia中找到值/变量的类型
- java参数可变方法
- python多线程下载编程_Python多线程结合队列下载百度音乐代码详解
- DDoS是什么意思?
- 怎么用计算机按反三角函数图像及性质,反三角函数图像及性质
- windows10搭建DVWA靶场(新手向)
- 【美影】通灵男孩诺曼.Paranorman
- QQ授权,接收代码发送的电子邮件
- ThinkPHP3.2.3 实现微信小程序微信授权登录
- 论文略读1《Direct training for spiking neural networks:faster,larger,better》
- a55计算机主板,A55架构简介与A55主板赏析
- AI时代-人工智能入学指南 - 迪哥有点愁
- 利用python将单个Excel文件转换为PDF
- 开源ERP软件Odoo提速指南
- 移动端嵌入式pdf展示
- 友基s400手写板怎么安装_手写板安装,教您电脑手写板怎么安装
热门文章
- 一个实例说明PID 参数整定
- 让iis支持二级域名泛解析
- 【论文阅读】CT-ICP: Real-time Elastic LiDAR Odometry with Loop Closure
- 7.读写HBase数据(华为云学习笔记,Spark编程基础,大数据)
- 计算机专业职业理想作文400字,理想的职业400字作文
- 干货!手把手教你如何快速了解一个行业--游戏产业概况
- 移民就移民了,别拉祖国来垫背
- java全栈系列之JavaSE-编写银行基金收益系统031
- Kubernetes集群Coredns组件的妙处(四十五)
- 红黑树(更高级的二叉查找树)