静态存储区和堆栈共33页文档
堆栈的定义及应用
堆栈的定义及应用堆栈(Stack)是一种数据结构,它按照后进先出(LIFO)的原则存储数据。
也就是说,最后存入堆栈的数据元素最先被取出,而最先存入的数据元素最后被取出。
堆栈中包含两个主要操作:压栈(Push)和弹栈(Pop)。
压栈是指将数据元素存入堆栈,弹栈是指从堆栈中取出数据元素。
除此之外,还有一个查看栈顶元素的操作。
堆栈的实际应用非常广泛,以下列举几个常见的应用场景:1. 函数调用与递归:在程序中,每当一个函数被调用,系统将会为这个函数分配一段内存空间,这段内存空间就被称为函数的栈帧。
当函数执行完毕后,栈帧会被销毁。
函数调用过程中,每次调用都会将返回地址和相关参数等信息压入栈中,在函数执行完毕后再将这些信息弹出。
递归函数的实现也离不开堆栈,每次递归调用都会生成一个新的栈帧,直到递归结束后才开始回溯弹栈。
2. 表达式求值:在编程语言中,堆栈可以用于实现算术表达式求值。
例如,中缀表达式需要通过堆栈进行转换成后缀表达式来简化计算过程,然后再通过堆栈进行后缀表达式的计算。
在进行表达式求值时,通过堆栈可以保存运算符和操作数的顺序,确保运算的优先级正确。
3. 括号匹配:在编程或者数学等领域,括号匹配是一个常见的问题。
我们可以使用堆栈来判断一个表达式中的括号是否匹配。
遍历表达式,每当遇到左括号时,将其压入堆栈。
当遇到右括号时,从堆栈中弹出一个左括号,若左右括号匹配,则继续遍历。
若右括号没有对应的左括号或者堆栈为空,则括号不匹配。
4. 浏览器的历史记录:在浏览器中,通过点击链接或者前进后退按钮,我们可以在不同的网页之间进行切换。
这种网页切换也可以使用堆栈来实现浏览历史记录的功能。
每当访问一个新网页时,将其URL压入堆栈顶部;当点击前进按钮时,从堆栈中弹出一个URL;当点击后退按钮时,将当前页面的URL压入堆栈,然后再弹出上一个URL。
5. 撤销与恢复:在许多软件中,都提供了撤销与恢复功能。
当用户对文档进行操作时,软件会将操作信息(如添加、删除、修改等)压入堆栈中,当用户点击撤销时,软件会从堆栈中弹出最近的操作信息并进行撤销操作;当用户点击恢复时,软件会从堆栈中弹出已经撤销的操作信息并进行恢复。
单片机C语言 必知的数据存储与程序编写知识 附单片机应用编程知识介绍
一、五大内存分区内存分成5个区,它们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
1、栈区(StaCk):FIFo就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。
里面的变量通常是局部变量、函数参数等。
2、堆区(heap):就是那些由new分配的内存块,它们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。
如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
3、自由存储区:就是那些由malloc等分配的内存块,它和堆是十分相似的,不过它是用free 来结束自己的生命。
4、全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
5、常量存储区:这是一块比较特殊的存储区,它们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)code/data/stack内存主要分为代码段,数据段和堆栈。
代码段放程序代码,属于只读内存。
数据段存放全局变量,静态变量,常量等,堆里存放自己malloc或new出来的变量,其他变量就存放在栈里,堆栈之间空间是有浮动的。
数据段的内存会到程序执行完才释放。
调用函数先找到函数的入口地址,然后计算给函数的形参和临时变量在栈里分配空间,拷贝实参的副本传给形参,然后进行压栈操作,函数执行完再进行弹栈操作。
字符常量一般放在数据段,而且相同的字符常量只会存一份。
二、C语言程序的存储区域1、由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过编译-汇编-连接三个阶段。
编译过程把C语言文本文件生成汇编程序,汇编过程把汇编程序形成二进制机器代码,连接过程则将各个源文件生成的二进制机器代码文件组合成一个文件。
2、C语言编写的程序经过编译-连接后,将形成一个统一文件,它由几个部分组成。
堆栈及静态数据区详解
堆、栈及静态数据区详解五大内存分区在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。
里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。
如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free 来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)明确区分堆与栈在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。
首先,我们举一个例子:void f() { int* p=new int[5]; }这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。
在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:00401028 push 14h0040102A call operator new (00401060)0040102F add esp,400401032 mov dword ptr [ebp-8],eax00401035 mov eax,dword ptr [ebp-8]00401038 mov dword ptr [ebp-4],eax这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete []p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie 信息去进行释放内存的工作。
编译原理第九章 运行时存储空间组织
– 堆区(new, malloc)
9.5 嵌套过程语言的栈式实现
• Pascal 的过程嵌套 嵌套层次:主程序0层 ······ 采用层数计数器,每逢Proc Begin加1,遇 Proc End则减1。
• 直接外层 • 编译器需要将过程的层数记录到符号表中
2)返回函数结果:累加器、寄存器
··· a:= 3 ··· P(a); Write(a); ···
传地址 8,8 8
举例
Procedure P(x) Begin
x:=x+5; writeln(x,a); End;
传结果 8,3 8
传值 8,3 3
举例
begin
Procedure P(x,y,z) …P(a+b,a,a)
初等类型数据采用确定“字长”,数组按列存放,边界对齐。
这样,可将过程活动单元(局部数据区)直接安排在 过程目标码之后,以便运行时访问。
9.3 Fortran静态存储分配(2)
数据区
返回地址 调用程序返回地址(调用恢复地址)
寄存器保护区 保存调用程序的寄存器运行环境
形式单元 形参
简单变量 数组 临时变量
P ->S ->Q =》R ->R
Program P; var a,x…
Top
R
procedure Q(b)
SP
var i…
R
procedure R(u,v)
动
var c,d…
态
begin… R… end {R} 链
Q
begin … R… end{Q} procedure S
网络安全与管理综合实训
网络安全与管理姓名:XXX学号:课程名称:网络安全与管理综合实训提交日期:2012年06月20日指导教师:概要本文分为网络安全和网络管理两部分,分别介绍了网络安全与网络管理所需使用的各种工具软件,通过图文介绍来知晓网络安全和网络管理中各种软件的作用及使用方法。
目录前言 (4)网络安全部分 (5)第一章目标系统探测 (5)1.1在线Web工具 (5)1.2 SmartWhois (5)1.3 Zenmap (6)1.4 X-scan (7)第二章口令破解 (10)2.1使用smbcrack对主机的口令进行破解 (10)第三章网络监听 (11)3.1使用Wireshark捕捉数据报 (11)第四章木马配置 (13)4.1冰河木马的配置 (13)第五章拒绝服务攻击 (15)5.1 DDoS攻击工具 (15)第六章缓冲区溢出 (17)6.1 OllDbg (17)第七章 PGP数据加密 (19)7.1加密的概念 (19)7.2数字签名概述 (19)7.3加密软件PGP( Pretty Good Privacy) (19)第八章防火墙应用 (21)8.1防火墙的定义 (21)8.2瑞星个人防火墙 (21)第九章 SSL安全设置 (24)第十章 ASP/SQL安全设置 (26)10.1 网站啄木鸟(WebPecker)-网站整体威胁检测系统 (26)10.2 WebPecker系统具备的功能 (26)10.3 WebPecker核心技术优势 (26)网络管理部分 (27)第一章 IP/MAC地址工具使用 (27)1.1 IP 地址扫描器 (27)1.2 超级扫描工具[super scan] (27)第二章 IP链路测试工具使用 (29)2.1 IP-Tools (29)2.2 网络信息工具WS_Ping ProPack (29)第三章网络查看与搜索工具使用 (31)3.1 超级网管(SuperLANadmin) (31)3.2 搜索工具 (32)第四章网络监管诊断分析工具使用 (34)4.1 网络监管专家———Red Eagle (34)4.2 查询分析工具 (35)第五章网络性能与带宽测试工具使用 (36)5.1 吞吐量测试工具-Qcheck (36)第六章流量监控与分析工具使用 (37)6.1 Essential NetTools (37)6.2 流量统计分析器利器-Comm View (38)第七章服务器监控工具使用 (40)7.1 监视各种服务与网络应用程序 (40)7.2 应用服务器的监视 (40)7.3 服务监视 (41)7.4 网站监视 (41)第八章网络维护与恢复工具使用 (43)8.1 网络维护工具 (43)8.2 Sql数据的备份与恢复 (46)结论 (47)致谢 (48)参考文献 (49)前言本实训项目通过对网络安全方面的目标系统探测、口令破解、网络监听、木马配置、拒绝服务攻击、缓冲区溢出、PGP数据加密、防火墙应用等及网络管理方面的IP/MAC地址工具使用、IP链路测试工具使用、网络查看与搜索工具使用、网络监管诊断分析工具使用、网络性能与带宽测试工具使用等工具和软件来对这两方面可能遇到的问题进行试验性分析。
内存中堆栈的划分
栈和堆的区别 (转) 终于知道区别了(2007-09-12 08:50:49)转载标签:IT/科技一个由 c/C++ 编译的程序占用的内存分为以下几个部分:1 、栈区( stack )—由编译器自动分配释放,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈。
2 、堆区( heap )—一般由程序员分配释放,若程序员不释放,程序结束时可能由 OS 回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3 、全局区(静态区)( static )—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
程序结束后由有系统释放。
4 、文字常量区—常量字符串就是放在这里的。
程序结束后由系统释放。
5 、程序代码区—存放函数体的二进制代码。
例子程序:这是一个前辈写的,非常详细//main.cppint a = 0; //全局初始化区char *p1; //全局未初始化区main(){int b; 栈char s[] = "abc"; //栈char *p2; //栈char *p3 = "123456"; //123456在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区p1 = (char *)malloc(10);p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}栈:在 Windows 下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。
这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS 下,栈的大小是 2M (也有的说是 1M ,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示 overflow 。
西安电子科技大学_计算机组成与体系结构_第4章存储系统_课件PPT
存取方式 读写功能
随机读写:RAM 顺序(串行)访问:
顺序存取存储器 SAM 直接存取存储器 DAM
12
4.1 存储系统概述 4.1.2 存储器分类:不同的分类标准
存储信息的介质
在计算机中的用途
存放信息的易失(挥发)性
存取方式 读写功能
读写存储器 只读存储器
13
存储信息的介质
在计算机中的用途 存放信息的易失(挥发)性 存取方式 读写功能
易失:RAM 非易失:
ROM 磁盘
……
11
4.1 存储系统概述 4.1.2 存储器分类:不同的分类标准
存储信息的介质 在计算机中的用途 存放信息的易失(挥发)性
存储器的存取时间 与存储单元的物理 地址无关,随机读 写其任一单元所用
无
36
8086系统总线
D0~D7
A1~A13 MEMR MEMW
A0
D8~D15 A1~A13 MEMR MEMW
BHE
&
A19
A18
A17
&
A16 A15 A14
6264与8086系统总线的连接
6264
D0~D7
A0~A12
CS1
OE
WE
CS2
6264
D0~D7
A0~A12
CS1
OE
WE
CS2
74LS138
每次读出/写入的字节数 存取周期
价格
体积、重量、封装方式、工作电压、环境条件
14
4.1 存储系统概述 4.1.2 存储器的性能指标
容量 速度 可靠性
可维修部件的可靠性: 平均故障间隔时间(MTBF)
堆栈的存储原则
堆栈的存储原则堆栈是一种特殊的数据结构,它根据特定的存储原则来保存数据,这种存储原则被称为“后进先出(Last In First Out, LIFO)”。
在堆栈中,数据元素按照一定的顺序进入栈中,这个顺序与它们离开栈的顺序相反。
栈顶始终指向最近添加到栈中的元素,而栈底则指向最先添加到栈中的元素。
堆栈的存储原则非常有用,因为它使得数据存储和检索变得非常高效。
我们可以使用堆栈来实现许多常见的算法和数据结构,例如递归,表达式求值,编译器等等。
堆栈的存储原则通常是通过数组或链表来实现的。
在使用数组实现堆栈时,我们需要确定堆栈的最大容量。
当我们向堆栈添加元素时,我们首先需要检查堆栈是否已经满了。
如果堆栈已满,则我们无法添加更多元素,而如果堆栈不满,则我们可以将元素添加到堆栈顶部。
当我们从堆栈中移除元素时,我们首先需要检查堆栈是否为空。
如果堆栈为空,则我们无法移除任何元素,而如果堆栈不为空,则我们可以将堆栈顶部的元素移除。
在使用链表实现堆栈时,我们不需要预先确定堆栈的最大容量。
当我们向堆栈添加元素时,我们可以动态地创建一个新节点并将其插入到链表的前面。
当我们从堆栈中移除元素时,我们可以简单地移除链表的头节点。
无论是使用数组还是链表实现堆栈,我们都需要注意几个关键点。
首先,当堆栈为空时,我们无法移除任何元素,因为没有元素可以移除。
因此,我们在移除元素之前必须首先检查堆栈是否为空。
其次,当使用数组实现堆栈时,我们必须确保我们不会超出堆栈的最大容量。
当使用链表实现堆栈时,我们必须确保我们正确地处理指针和节点位置,以确保堆栈的正确性。
总的来说,堆栈的存储原则对于许多算法和数据结构都非常有用。
无论使用数组还是链表实现堆栈,我们必须遵循一定的规则来确保堆栈的正确性。
熟练掌握堆栈的存储原则,将有助于我们更好地理解和设计各种复杂的算法和数据结构。
局部变量与全局变量区别栈、堆和静态存储区的区别
从作用域看:全局变量具有全局作用域.全局变量只需在一个源文件中定义,就可以作用于所有地源文件.当然,其他不包括全局变量定义地源文件需要用关键字再次声明这个全局变量.个人收集整理勿做商业用途静态局部变量具有局部作用域.它只被初始化一次,自从第一次初始化直到程序与你新内阁结束都一直存在,他和全局变量地区别在于全局变量对所有地函数都是可见地,而静态局部变量只对定义自己地函数体始终可见.个人收集整理勿做商业用途局部变量也只有局部作用域,他是自动对象,他在程序运行期间不是一直存在,而是只在函数执行期间存在,函数地一次调用结束后,变量就被撤销,其所占用地内存也被收回.个人收集整理勿做商业用途静态全局变量也具有全局作用域,他与全局变量地区别在于如果程序包含多个文件地话,他作用于定义它地文件里,不能作用到其他文件里,即被关键字修饰过地变量具有文件作用域.这样即使两个不同地源文件都定义了相同地静态全局变量,他们也是不同地变量.个人收集整理勿做商业用途从分配内存空间看:全局变量、静态局部变量、静态全局变量都在静态存储区分配空间,而局部变量在栈分配空间.全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式.这两者在存储方式上没有什么不同.区别在于非静态全局变量地作用域是整个源程序,当一个源程序由多个源文件组成时,非静态地全局变量在各个源文件中都是有效地.而静态全局变量则限制了其作用域,即只在定义该变量地源文件内有效,在同一源程序地其他源文件中不能使用它.由于静态全局变量地作用域局限于一个源文件内,只能为该源文件内地函数公用,因此可以避免在其他源文件中引起错误.个人收集整理勿做商业用途、静态变量会被放在程序地静态数据存储区里,这样可以在下一次调用地时候还可以保持原来地赋值.这一点是他与堆栈变量和堆变量地区别个人收集整理勿做商业用途、变量用告知编译器,自己仅仅在变量地作用域范围内可见.这一点是他与全局变量地区别.从以上分析可以看出,把局部变量改变为静态变量后是改变了他地存储方式,即改变了他地生存期.把全局变量改变为静态变量后是改变了他地作用域,限制了他地使用范围,因此这个说明符在不同地地方起地作用是不同地.个人收集整理勿做商业用途:、若全局变量仅在单个文件中访问,则可以讲这个变量修改为静态全局变量.、若全局变量仅在单个函数中使用,则可以将这个变量修改为该函数地静态局部变量.、全局变量、静态局部变量、静态全局变量都存放在静态数据存储区.、函数中必须要使用变量地情况:当某函数地返回值为指针类型时,则必须是地局部变量地地址作为返回值,若为类型,则返回为错指针.个人收集整理勿做商业用途个人收集整理勿做商业用途预备知识—程序地内存分配一个由编译地程序占用地内存分为以下几个部分栈区()—由编译器自动分配释放,存放函数地参数值,局部变量地值等.其操作方式类似于数据结构中地栈. 个人收集整理勿做商业用途堆区()—一般由程序员分配释放,若程序员不释放,程序结束时可能由回收 .注意它与数据结构中地堆是两回事,分配方式倒是类似于链表. 个人收集整理勿做商业用途全局区(静态区)()—,全局变量和静态变量地存储是放在一块地,初始化地全局变量和静态变量在一块区域,未初始化地全局变量、未初始化地静态变量在相邻地另一块区域. 程序结束后有系统释放个人收集整理勿做商业用途文字常量区—常量字符串就是放在这里地.程序结束后由系统释放程序代码区—存放函数体地二进制代码.一个正常地程序在内存中通常分为程序段、数据端、堆栈三部分.程序段里放着程序地机器码、只读数据,这个段通常是只读,对它地写操作是非法地.数据段放地是程序中地静态数据.动态数据则通过堆栈来存放.个人收集整理勿做商业用途在内存中,它们地位置如下:内存低端程序段数据段堆栈内存高端个人收集整理勿做商业用途堆栈是内存中地一个连续地块.一个叫堆栈指针地寄存器()指向堆栈地栈顶.堆栈地底部是一个固定地址.堆栈有一个特点就是,后进先出.也就是说,后放入地数据第一个取出.它支持两个操作,和.是将数据放到栈地顶端,是将栈顶地数据取出.在高级语言中,程序函数调用、函数中地临时变量都用到堆栈.为什么呢?因为在调用一个函数时,我们需要对当前地操作进行保护,也为了函数执行后,程序可以正确地找到地方继续执行,所以参数地传递和返回值也用到了堆栈.通常对局部变量地引用是通过给出它们对地偏移量来实现地.另外还有一个基址指针(,在芯片中是),许多编译器实际上是用它来引用本地变量和参数地.通常,参数地相对地偏移是正地,局部变量是负地.当程序中发生函数调用时,计算机做如下操作:首先把参数压入堆栈;然后保存指令寄存器()中地内容,做为返回地址();第三个放入堆栈地是基址寄存器();然后把当前地栈指针()拷贝到,做为新地基地址;最后为本地变量留出一定空间,把减去适当地数值.在函数体中定义地变量通常是在栈上,用, , 等分配内存地函数分配得到地就是在堆上.在所有函数体外定义地是全局量,加了修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义地变量表示在该文件中有效,不能到别地文件用;在函数体内定义地表示只在该函数体内有效.另外,函数中地""这样地字符串存放在常量区.对比:个人收集整理勿做商业用途性能栈:栈存在于中.栈是动态地,它地存储速度是第二快地.堆:堆位于中,是一个通用地内存池.所有地对象都存储在堆中.申请方式【栈】: 由系统自动分配. 例如,声明在函数中一个局部变量; 系统自动在栈中为开辟空间 .【堆】: 需要程序员自己申请,并指明大小,在中函数如( *)(); 在中用运算符如( *)(); 但是注意:、本身是在栈中地.申请后系统地响应栈【】:只要栈地剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出. 个人收集整理勿做商业用途堆【】:首先应该知道操作系统有一个记录空闲内存地址地链表,当系统收到程序地申请时,会遍历该链表,寻找第一个空间大于所申请空间地堆结点,然后将该结点从空闲结点链表中删除,并将该结点地空间分配给程序;另外,对于大多数系统,会在这块内存空间中地首地址处记录本次分配地大小,这样,代码中地语句才能正确地释放本内存空间.另外,由于找到地堆结点地大小不一定正好等于申请地大小,系统会自动地将多余地那部分重新放入空闲链表中.申请大小地限制栈【】:在下,栈是向低地址扩展地数据结构,是一块连续地内存地区域.这句话地意思是栈顶地地址和栈地最大容量是系统预先规定好地,在下,栈地大小是(也有地说是,总之是一个编译时就确定地常数),如果申请地空间超过栈地剩余空间时,将提示.因此,能从栈获得地空间较小. 个人收集整理勿做商业用途堆【】:堆是向高地址扩展地数据结构,是不连续地内存区域.这是由于系统是用链表来存储地空闲内存地址地,自然是不连续地,而链表地遍历方向是由低地址向高地址.堆地大小受限于计算机系统中有效地虚拟内存.由此可见,堆获得地空间比较灵活,也比较大.申请效率地比较栈【】:由系统自动分配,速度较快.但程序员是无法控制地. 个人收集整理勿做商业用途堆【】:是由分配地内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.另外,在下,最好地方式是用分配内存,他不是在堆,也不是在栈是直接在进程地地址空间中保留一快内存,虽然用起来最不方便.但是速度快,也最灵活.堆和栈中地存储内容栈【】:在函数调用时,第一个进栈地是主函数中后地下一条指令(函数调用语句地下一条可执行语句)地地址,然后是函数地各个参数,在大多数地编译器中,参数是由右往左入栈地,然后是函数中地局部变量.注意静态变量是不入栈地. 个人收集整理勿做商业用途当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存地地址,也就是主函数中地下一条指令,程序由该点继续运行.堆【】:一般是在堆地头部用一个字节存放堆地大小.堆中地具体内容有程序员安排.存取效率地比较[] "";* "";是在运行时刻赋值地;而是在编译时就确定地;但是,在以后地存取中,在栈上地数组比指针所指向地字符串(例如堆)快.比如:(){;[] "";* "";[];[];;}对应地汇编代码: [];[][]: [];[][][]第一种在读取时直接就把字符串中地元素读到寄存器中,而第二种则要先把指针值读到中,在根据读取字符,显然慢了.小结:堆和栈地区别可以用如下地比喻来看出:使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他地好处是快捷,但是自由度小.使用堆就象是自己动手做喜欢吃地菜肴,比较麻烦,但是比较符合自己地口味,而且自由度大.个人收集整理勿做商业用途。
内存中的五大区
2.生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
3.分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax
这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete []p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。
4.分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
1.碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以>参考数据结构,这里我们就不再一一讨论了。
堆栈段寄存器
2.1 8086/8088微处理器的结构
图2-3 存储器的逻辑分段结构
2.1 8086/8088微处理器的结构
3. 物理地址和逻辑地址 • 在有地址变换机构的计算机系统中,每个存储单 元可以看成具有两种地址:物理地址和逻辑地址。 • 物理地址是信息在存储器中实际存放的地址(20 位),它是CPU访问存储器时实际输出的地址。 物理地址与存储单元是一一对应关系。 • 逻辑地址是编程时所使用的地址(16位),对所 给定的任一存储单元而言有逻辑地址由“段基址” 和“段内偏移量”两部分构成。一个逻辑地址只 能对应一个物理地址,而一个物理地址可以对应 多个逻辑地址。
2.1 8086/8088微处理器的结构
• 段基址:说明逻辑段在内存中的起始位置。 • 段内偏移量:说明主存单元距离段起始位置的偏 移量。 • 段基址存放在段寄存器CS、SS、DS和ES中。 • 段内偏移量由SP、BP、SI、DI、IP以及相应寄 存器的组合而组成。 • 逻辑地址表示形式:
例2.2:BBH + 6AH=(1)25H 无符号数运算:187+106=293 范围外,有进位 有符号数运算: -69+106=37 范围内,无溢出
2.1 8086/8088微处理器的结构
例2.3: 1101 0010 + 0110 0110 1 0011 1000 例2.4: 0101 0001 0100 1011 + 0110 0010 0100 0110 1011 0011 1001 0001
执行部件EU从指令队列取指 令,并执行。
2.1 8086/8088微处理器的结构
2.1.3 存储器中的逻辑地址和物理地址 1. 为什么要采用存储器“分段”技术? • 8086/8088系统有20根地址总线,它可以直接寻 址的存储器单元数为220=1MB。 • 而微处理器中所有的寄存器都是16位的,内部 ALU也只能进行16位运算,其寻址范围局限在216 =65536(64KB)单元。 • 为了实现对1MB单元的寻址,8086系统采用了存 储器分段技术。
实验周堆栈实验报告
一、实验目的1. 理解堆栈的基本概念和原理。
2. 掌握堆栈的存储结构和操作方法。
3. 熟悉堆栈在程序设计中的应用。
二、实验原理堆栈(Stack)是一种先进后出(FILO)的数据结构,其基本原理是:在堆栈中插入或删除元素时,总是从栈顶开始操作。
堆栈的存储结构可以是数组、链表等。
三、实验环境1. 操作系统:Windows 102. 编程语言:C语言3. 开发环境:Visual Studio 2019四、实验内容与步骤1. 堆栈的定义与初始化首先,我们需要定义一个堆栈的数据结构,包括堆栈的存储空间、最大容量、栈顶指针等。
以下是用C语言定义堆栈的示例代码:```c#define MAX_SIZE 100typedef struct {int data[MAX_SIZE]; // 存储空间int top; // 栈顶指针} Stack;```然后,初始化堆栈,将栈顶指针置为-1,表示堆栈为空。
```cvoid InitStack(Stack s) {s->top = -1;}```2. 堆栈的入栈操作入栈操作是指在堆栈的栈顶插入一个新元素。
以下是实现入栈操作的代码:```cint IsFull(Stack s) {return s->top == MAX_SIZE - 1;}int Push(Stack s, int element) {if (IsFull(s)) {return 0; // 栈满}s->data[++s->top] = element;return 1;}```3. 堆栈的出栈操作出栈操作是指从堆栈中删除栈顶元素。
以下是实现出栈操作的代码:```cint IsEmpty(Stack s) {return s->top == -1;}int Pop(Stack s, int element) {if (IsEmpty(s)) {return 0; // 栈空}element = s->data[s->top--];return 1;}```4. 堆栈的遍历操作遍历操作是指依次访问堆栈中的所有元素。
C语言内存管理堆栈和静态存储区
C语言内存管理堆栈和静态存储区C语言内存管理:堆、栈和静态存储区C语言作为一种高效而强大的编程语言,其内存管理是程序员必须掌握的重要内容之一。
本文将重点介绍C语言中的内存管理中的堆、栈以及静态存储区。
一、堆堆是C语言中用于动态内存分配的一块内存区域。
在程序运行时,可以通过函数malloc()和calloc()来申请堆空间,通过函数free()来释放堆空间。
堆的特点:1. 大小可变:堆中的内存空间大小可以在程序运行时进行动态调整。
2. 生命周期自由控制:通过malloc()或calloc()分配的堆空间,在不再使用后,需要程序员手动调用free()函数进行释放。
堆的使用场景:1. 动态数组:当程序无法预先知道数组大小时,可以使用堆来动态申请空间。
2. 链表:链表结构通常需要通过堆来进行动态内存分配。
二、栈栈是C语言中用于函数调用和局部变量存储的一块内存区域。
在函数调用过程中,栈会记录函数的调用顺序、调用参数以及局部变量等。
栈的特点:1. 后进先出:栈是一种后进先出(LIFO)的数据结构,函数调用时会依次将函数入栈,并在函数返回时依次出栈。
2. 自动管理:栈内存的分配和释放是由编译器自动完成的,程序员无需手动管理。
栈的使用场景:1. 函数调用:栈用于管理函数的调用顺序以及函数内部的局部变量。
2. 递归:递归函数的调用过程涉及到栈的递归压栈和递归出栈。
三、静态存储区静态存储区是C语言中使用static关键字声明的变量所存储的内存区域。
在程序运行期间,静态变量在内存中的位置始终不变,且仅在程序结束时才会释放。
静态存储区的特点:1. 生命周期长:静态变量在程序运行期间都存在,不依赖于函数的调用和返回。
2. 全局可访问:静态变量可以在整个程序中被访问,不受函数作用域的限制。
静态存储区的使用场景:1. 全局变量:使用static关键字声明的全局变量存储在静态存储区中,可以在整个程序中被访问。
2. 共享数据:多个函数之间需要共享的数据可以使用静态变量来实现。
数据区代码区堆栈区操作系统堆栈
数据区代码区堆栈区操作系统堆栈
数据区、代码区、堆栈区是计算机内存的三个重要组成部分。
其中数据区主要用于存储程序的全局变量和静态变量;代码区用于存储程序的指令;堆栈区用于存储函数的局部变量和调用栈信息;操作系统堆栈是操作系统用于管理进程和线程信息的内存区域。
数据区是程序执行过程中存储数据的地方。
它包括全局变量和静态变量。
全局变量是声明在函数体外的变量,在程序整个运行过程中都可见。
静态变量是在函数内部用关键字static声明的变量,它的生命周期和程序执行过程中的其他变量不同,它在整个程序的执行过程中都会存在。
代码区是存储程序指令的地方。
在程序执行过程中,计算机会将程序代码从磁盘加载到内存的代码区,并按照指令的顺序依次执行。
代码区是只读的,程序无法对其进行修改。
堆栈区是用于存储函数的局部变量和调用栈信息的地方。
当一个函数被调用时,在堆栈区会为该函数分配一块内存空间,用于存储该函数的局部变量。
而调用栈用于保存函数的调用关系和返回地址等信息,以便在函数调用完成后能正确地返回到调用函数。
操作系统堆栈是操作系统用于管理进程和线程信息的内存区域。
操作系统为每个进程和线程分配一块堆栈内存,在进程和线程的运行过程中,堆栈用于保存上下文信息和函数调用栈,以便操作系统能够正确地管理和调度它们。
总结起来,数据区用于存储程序的全局变量和静态变量;代码区用于存储程序的指令;堆栈区用于存储函数的局部变量和调用栈信息;操作系统堆栈是操作系统用于管理进程和线程信息的内存区域。
这些区域在计算
机内存中起到不同的作用,各自负责不同的功能,共同构成了计算机的内存体系。
c语言中的堆栈
c语言中的堆栈摘要:1.堆栈的概念与作用2.C语言中的堆栈实现3.堆栈的使用方法与注意事项4.堆栈溢出的原因及预防5.堆栈在编程中的应用实例正文:堆栈是计算机科学中一种重要的数据结构,主要用于实现函数调用、局部变量存储以及算法递归等功能。
在C语言中,堆栈有着广泛的应用,下面我们将详细介绍堆栈的相关知识。
1.堆栈的概念与作用堆栈是一种线性数据结构,遵循后进先出(LIFO)的原则。
堆栈分为栈顶和栈底,数据元素在栈中按照顺序排列,只有栈顶元素可以被访问和修改,其他元素则无法直接访问。
堆栈的主要作用有以下几点:- 函数调用:C语言中,函数调用是通过堆栈来实现的。
每当一个函数被调用,它的局部变量、返回地址等信息会被压入堆栈。
函数执行完毕后,堆栈会将这些信息弹出,恢复调用者的状态。
- 局部变量存储:在C语言中,局部变量的存储也是通过堆栈来实现的。
当进入一个函数时,局部变量会被压入堆栈;函数执行完毕后,局部变量会被自动弹出。
- 算法递归:递归算法通常使用堆栈来保存递归调用时的中间结果,从而避免重复计算。
2.C语言中的堆栈实现C语言中的堆栈是由操作系统提供的,通常使用一组固定大小的内存区域来实现。
堆栈的增长方向是向下的,堆栈指针指向栈顶元素。
在C语言中,堆栈的操作主要包括入栈(push)和出栈(pop)两种。
3.堆栈的使用方法与注意事项使用堆栈时,需要注意以下几点:- 避免堆栈溢出:堆栈空间是有限的,如果栈中的元素数量过多,会导致堆栈溢出。
因此,在使用堆栈时,需要合理控制栈的大小,避免长时间递归调用或大量使用局部变量。
- 遵循栈的生长方向:在C语言中,堆栈的生长方向是向下的,因此入栈操作会使栈顶指针减小,出栈操作会使栈顶指针增大。
- 注意栈的操作顺序:在函数调用中,先入栈的是函数的返回地址,然后是局部变量;函数执行完毕后,首先弹出的是局部变量,然后是返回地址。
4.堆栈溢出的原因及预防堆栈溢出是由于栈中的元素数量过多,导致栈空间不足而引发的。
局部变量、全局变量、堆、堆栈、静态和全局变量
局部变量、全局变量、堆、堆栈、静态和全局变量一般全局变量存放在数据区,局部变量存放在栈区,动态变量存放在堆区,函数代码放在代码区。
---------------------------------------------------------------栈区是普通的栈数据结构,遵循LIFO后进先出的规则,局部变量安排在那里是ASM时就规定的,这样可以在一个函数结束后平衡堆栈,操作简单,效率高堆(动态区)在这里应当叫堆栈(不要和数据结构中的堆搞混)是程序在编译时产生的一块用于产生动态内存分配使用的块,操作比较栈要麻烦许多,在分配时要判断最优的地址(防止产生无用的内存碎片(由于屡次的NEW和DELETE产生的夹在两块使用中内存中的空余小内存(不容易被分配))),分配和回收时的效率比栈低多了---------------------------------------------------------------栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而堆是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率>有一定降低。
栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。
不同堆分配的内存无法互相操作。
栈空间分静态分配和动态分配两种。
静态分配是编译器完成的,比如自动变量(auto)的分配。
动态分配由malloca函数完成。
栈的动态分配无需释放(是自动的),也就没有释放函数。
为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/ 释放内存匹>配是良好程序的基本要素。
堆是程序员管理的,栈是系统管理的.另外关于静态和全局的一些问题:静态变量的特点:1、一次存储:静态局部变量只被初始化一次,下一次初始化根据上一次的结果值,有点类似于c++中类的静态成员变量,即无论该类型生成多少个实例对象,所有的对象共用一个静态变量,到这里就是无论这个函数调用多少次,该静态变量只初始化一次,并没有因为超出其生存期而被销毁,只是外部不可见而已,用个例子说明之:void fun1( int v ){static int value = v;static int value = v;}int main( int arc, char*args[ ]){fun1( 50 );fun1( 100 );}执行的结果是:value : 50 value : 50说明在第二次调用fun1( )时的初始化value的采用的是上一次value的值,value在静态区的存储空间并没有因为fun1( )的结束而被释放,即体现了一次存储;2、作用域限定:静态修饰的作用域限定功能同时体现在函数与变量上;a)对于函数而言,任何用static修饰的函数,其作用域仅为当前源文件,而对外部来说这个函数是不可见的,即只有和其在同一源文件中的函数才能调用这个静态函数;反过来说,如果一个函数仅仅被同一源文件中的其他函数调用,那么这个函数应该声明为静态的,这样做的好处在于:可以一定程度上的解决不同源文件之间函数的命名冲突问题;b)对于变量而言,static修饰的全局变量,只在当前源文件中有效,对外部不可见,外部文件不能够引用;顾名思义,全局变量是指能够在全局引用的变量,相对于局部变量的概念,也叫外部变量;同静态变量一样,全局变量位于静态数据区,全局变量一处定义,多处引用,用关键字“extern”引用“外部”的变量。
栈的存储结构
栈的存储结构栈:线性结构,后进先出。
栈(Stack)是⼀种特殊的线性表(顺序表,链表)只在表尾进⾏删除和插⼊操作。
注意:对于栈来说,表尾称为栈的栈顶(top),表头称为栈底(bottom)。
栈也是线性结构的⼀种特例。
与队列不同,他只有⼀个⼝,只能从这⾥读或者写数据,这个⼝称为栈顶(top )。
栈是⼀种先进后出的。
先进来的元素会放⼊栈底,⽽后进来的元素被放在它的上⾯,最后进来的元素的上⾯的位置,称为栈顶。
栈所提供的操作⽐⼀般的线性表要少很多,只提供:初始化、销毁、判断是否为空、求栈的长度、清空栈、将数据压⼊栈、将数据弹出栈、获得栈顶元素这⼏种操作。
其中将数据压⼊栈、将数据弹出栈、获得栈顶元素是最重要的。
有⼈可能觉得,将栈顶元素弹出与获得栈顶元素是不是有点重复,其实它们主要的⽬的在于,很多时候你只想知道当前栈顶的元素是谁,⽽并不想将它弹出。
这样做可以简单⼀点。
了解了栈的基本结构和操作以后,⾃然⽽然的想到⽤数组来实现栈:因为前⾯的元素并不发⽣变化,只能在最后⾯⼊栈或者出栈。
因为栈的本质是⼀个线性表,线性表有两种存储形式,那么栈也有分为栈的顺序存储结构和栈的链式存储结构。
最开始栈中不含有任何数据,叫做空栈,此时栈顶就是栈底。
然后数据从栈顶进⼊,栈顶栈底分离,整个栈的当前容量变⼤。
数据出栈时从栈顶弹出,栈顶下移,整个栈的当前容量变⼩。
栈顶——地址较⾼;栈底——地址较低。
定义⼀个顺序存储的栈,包含三个元素:base 、top 、stackSize 。
或者:其中base 是指栈底的指针变量,top 是指栈顶的指针变量,stackSize 指栈的当前可使⽤的最⼤容量。
创建⼀个栈:⼊栈操作:⼊栈操作⼜叫压栈操作,就是向栈中存放数据。
⼊栈操作要在栈顶进⾏,每次向栈中压⼊⼀个数据,top 指针就要+1,直到栈满为⽌。
[cpp]01. typedef struct { 02. ElemType *base;//栈底 03. ElemType *top;//栈顶 04. int stackSize;//栈的当前可使⽤的最⼤容量 05. }sqStack; [cpp]01. typedef int ElemType; 02. typedef struct { 03. ElemType data[MAXSIZE]; 04. int top; // ⽤于标注栈顶的位置 05. int stackSize; 06. } [cpp]01. #define STACK_INIT_SIZE 100 02. 03. initStack(sqStack *s){ 04. s->base = (ElemType *)malloc( STACK_INIT_SIZE * sizeof (ElemType) ); 05. if ( !s->base ) 06. exit(0); 07. 08. s->top = s->base; // 最开始,栈顶就是栈底 09. s->stackSize = STACK_INIT_SIZE; 10. }出栈操作:出栈操作就是在栈顶取出数据,栈顶指针随之下移的操作。
计算机中堆栈的概念
计算机中堆栈的概念这两天学习win32的API,了解到了计算机中堆栈的概念,相信很多程序员有时候也弄不明⽩计算机中的堆栈的。
再次为堆栈做⼀下详细解析。
在英⽂中,我们管栈称为stack,管堆称为heap。
在计算机中,堆栈是两种不同的数据结构,但堆栈均为⼀种按序排列的数据结构。
只能在⼀端对数据项进⾏插⼊和删除。
其中的关键是,堆,的排列顺序是随意的,⽽栈,排列顺序是先进后出(First In Last Out)。
堆:为编译器⾃动的分配与释放,⽤来存放函数的参数值与局部变量。
其操作⽅式类似于数据结构中的栈。
栈使⽤的是⼀级缓存,通常都是在调⽤时候存储于存储空间中,在⽤完后由编译器⾃动的释放。
堆:为编程⼈员分配与释放,如果在程序结束的时候没有释放,⼀般会被OS所回收,分配⽅式类似于链表。
堆⼀般存储于⼆级缓存。
数据结构,堆可以被看成⼀棵树。
栈则是⼀种先进后出的数据结构。
在具体介绍之前,我们应该介绍⼀下在C或者C++语⾔中变量的存储区域。
1,栈区(stack):这块区域由编译器分配与释放内存空间,⼀般存储函数的参数值与局部变量值。
类似于数据结构中的栈。
2,堆区(heap):这块区域由程序员⾃⼰分配与释放,其余数据结构中的堆是两码事,分配⽅式类似于链表。
3,全局区(静态变量区):这块存储区域⽤于存储全局变量(global)和静态变量(static),初始化的全局变量和静态变量存储于⼀块区域,未初始化的全局变量和静态变量存储于另⼀块区域。
程序结束后系统⾃动释放。
4,⽂字常量区(静态缓冲区):这块区域⽤于存储常量静态字符串,在前⾯⽂章我有提到过并且演⽰过,⽤于存放const char*类型的变量。
在程序运⾏中,是不可能对其进⾏修改的,如果修改的话,程序将会报错并且crush,程序结束后由系统⾃动释放。
5,程序代码区:该区域⽤于存放函数体的⼆进制代码。
下⾯,我⽤⼀段程序来解释在什么地⽅存放各种变量。
上⾯的例⼦完全诠释了各种变量存储的地⽅在程序中。
堆栈知识详解(简单易懂)ppt课件
最新编辑ppt
15
Push函数
template<class T> Stack<T>& Stack<T>::Push(const T& x) {// Push x to stack.
if (IsFull()) throw NoMem(); // Push fails stack[++top] = x; return *this; }
信息技术科学学院
最新编辑ppt
29
Pop
template<class T> LinkedStack<T>& LinkedStack<T>::Pop(T& x) {// Delete top element and put it in x.
if (IsEmpty()) throw OutOfBounds(); x = top->data; Node<T> *p = top; top = top->link; delete p; return *this; }
try {ChainNode<T> *p = new ChainNode<T>;
delete p;
return false;}
catch (NoMem) {return true;}
}
• 笨拙! 信息技术科学学院
最新编辑ppt
23
H2.自定义的链表实现
template <class T> class Node {
catch (NoMem) {return true;} }
信息技术科学学院
最新编辑ppt
STM32堆栈分析
三、STM32堆栈区预备知识:一个由C/C++编译的程序占用的内存分为以下几个部分:●栈区(stack):编译器自动分配释放,存放函数的参数值,局部变量的值等。
操作方式类似于数据结构中的栈。
●堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
●全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
程序结束后由系统释放。
●文字常量区—常量字符串就是放在这里的。
程序结束后由系统释放●程序代码区—存放函数体的二进制代码编译后,各个区存储内容举例说明如下://main.cppint a = 0; 全局初始化区char *p1; 全局未初始化区main(){int b; 栈char s[] = “abc”; 栈char *p2; 栈char *p3 = “123456”; 123456\0在常量区,p3在栈上static int c =0;全局(静态)初始化区p1 = (char *)malloc(10);p2 = (char *)malloc(20);分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}STM32的分区STM32的分区从0x2000 0000(0x2000 0000是SRAM的起始地址,由此可知,堆栈等都是在RAM中的)开始。
静态区,堆,栈。
所有的全局变量,包括静态变量之类的,全部存储在静态存储区。
紧跟静态存储区之后的,是堆区(如没用到malloc,则没有该区),之后是栈区,栈在程序中存储局部变量。
先看启动文件startup_stm32f10x_md.s的定义:; Amount of memory (in bytes) allocated for Stack; Tailor this value to your application needs; <h> Stack Configuration; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_Size__initial_sp; <h> Heap Configuration; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Heap_Size EQU 0x00000200AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limit这里定义了堆栈各自大小,堆:512bytes 栈1k;所以栈区大小有限制,我们在局部变量中不要定义大数组否则容易溢出。