C++堆栈与函数调用

一、C++程序内存分配

1)在栈上创建。在执行函数时,函数内局部变量的存储单元都在栈上创建,函数结束是,这些存储单元自动被释放。栈内存的分配运算内置于处理器的指令集中,一般采用寄存器来存取,效率很高但是分配的内存容量有限。

2)从堆上分配,亦称动态内存分配。程序在运行时malloc或new任意多的内存,程序员自己负责在何时用free和Delete来释放内存。动态内存的生存周期由程序员自己决定,使用非常灵活。

3)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量。

4)文字常量分配在文字常量区,程序结束后由系统释放。

5)程序代码区。

下面举个例子:

 1 #include<string.h>
 2 #include<stdlib.h>
 3 int a=0;    //全局初始化区
 4 char *p1;   //全局未初始化区
 5 int main()
 6 {
 7     int b;  //栈
 8     char s[]="abc";//栈
 9     char *p2;   //栈
10     char *p3="12345";    //12345\0在常量区,p3在栈上
11     static int c=0;     //全局(静态)初始化区
12     p1=(char *)malloc(10);
13     p2=(char *)malloc(20);  //分配得来的10和20个字节在堆上
14     strcpy(p1,"12345"); //12345\0放在常量区,编译器可能会将它与p3所指向的“12345”优化成一个地方
15     return 0;
16 }

二、三种内存对象的比较

  栈对象的优势是在适当的时间自动生成,又在适当的时间自动销毁,不需要程序员操心;而栈对象的创建速度一般较堆对象快,因为分配堆对象时,会调用operate new操作,operate new操作会采用某种内存空间搜索算法,而这个搜索过程可能是很浪费时间的,产生栈对象没有这么麻烦,它仅仅需要移动栈顶指针就行了。但是,要注意的是,通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。特别要注意在递归函数中最好不要使用栈对象,因为随着递归调用深度的增加,所需要的栈空间也会线性增加,当所需栈空间不够时,便会导致栈溢出,这样就会产生运行时错误。

  堆对象创建和销毁都要程序员负责,所以,如果处理不好,就会发生内存问题。如果分配了堆对象却忘记了释放就会产生内存泄露;如果已经释放了对象,却没有将相应的指针置为NULL,该指针就是所谓的“悬挂指针”,再度调用此指针就会出现非法访问,严重时导致程序崩溃。但是高效地使用堆对象也可以大大提高代码质量。比如我们需要创建一个大对象,且需要被多个函数访问,那么这个时候创建一个堆对象无疑是良好的选择,因为我们通过在各个函数之间传递这个堆对象的指针,便可以实现对该对象的共享,相比整个对象的传递,大大降低了对象的拷贝时间。另外,相比于栈空间,堆的容量要大的多,甚至在物理内存不够时,如果这时还需要创建新的堆对象,通常不会产生运行是错误,而是系统会使用虚拟内存来扩展实际的物理内存。

  静态存储区。所有的全局对象、静态对象都在静态存储区分配。全局对象时在main()函数执行之前就分配好了的。其实,在main函数的显示代码之前,会调用一个由编译器生成的_main()函数,而_main()函数会进行所有全局对象的构造和初始化工作。而在main()函数结束之前,会调用由编译器生成的exit函数,来释放所有的全局对象。

比如下面的代码:

void main()

{

  //显式代码

}

实际上被转化成这样

void main()

{

  _main();  //隐式代码,由编译器产生,用于构造所有全局对象

  ...   ...;   //显式代码

  exit();    //隐式代码,由编译器产生,用于释放所有全局对象

}

时间: 2024-08-17 01:00:13

C++堆栈与函数调用的相关文章

ARM处理器的堆栈和函数调用,以及与Sparc的比较

主要内容来自以下网址.该网站是个学习ARM汇编的好地方.计划将该篇文章翻译过来,并和Sparc对比. https://azeria-labs.com/functions-and-the-stack-part-7/ ARM和Sparc比较 之前整理的Sparc的原理,Sparc V8 汇编指令.寄存器窗口.堆栈.函数调用,https://www.cnblogs.com/yanhc/p/12255886.html 关于函数调用的跳转执行 ARM跳转有BL指令,Branch Link(Saves (P

函数调用约定和堆栈

函数调用约定和堆栈 1 什么是堆栈 编译器一般使用堆栈实现函数调用.堆栈是存储器的一个区域,嵌入式环境有时需要程序员自己定义一个数组作为堆栈.Windows为每个线程自动维护一个堆栈,堆栈的大小可以设置.编译器使用堆栈来堆放每个函数的参数.局部变量等信息. 函数调用经常是嵌套的,在同一时刻,堆栈中会有多个函数的信息,每个函数占用一个连续的区域.一个函数占用的区域被称作帧(frame). 编译器从高地址开始使用堆栈. 假设我们定义一个数组a[1024]作为堆栈空间,一开始栈顶指针指向a[1023]

堆栈溢出

1.基础知识. 在x86处理器中:EIP(Instruction Pointer)是指令寄存器,指向处理器下条等待执行的指令地址(代码段内的偏移量),每次执行完相应汇编指令EIP值就会增加. ESP(Stack Pointer)是堆栈指针寄存器,存放执行函数对应栈帧的栈顶地址(也是系统栈的顶部),且始终指向栈顶: EBP(Base Pointer)是栈帧基址指针寄存器,存放执行函数对应栈帧的栈底地址,用于C运行库访问栈中的局部变量和参数. 从物理上讲,堆栈是就是一段连续分配的内存空间.在一个程序

一步一步写算法(之线性堆栈)

原文:一步一步写算法(之线性堆栈) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面我们讲到了队列,今天我们接着讨论另外一种数据结构:堆栈.堆栈几乎是程序设计的命脉,没有堆栈就没有函数调用,当然也就没有软件设计.那么堆栈有什么特殊的属性呢?其实,堆栈的属性主要表现在下面两个方面: (1)堆栈的数据是先入后出 (2)堆栈的长度取决于栈顶的高度 那么,作为连续内存类型的堆栈应该怎么设计呢?大家可以自己先试一下: (1)设计堆栈节点 typ

01-(2)数据结构- 一步一步写算法(之线性堆栈)

前面我们讲到了队列,今天我们接着讨论另外一种数据结构:堆栈.堆栈几乎是程序设计的命脉,没有堆栈就没有函数调用,当然也就没有软件设计.那么堆栈有什么特殊的属性呢?其实,堆栈的属性主要表现在下面两个方面: (1)堆栈的数据是先入后出 (2)堆栈的长度取决于栈顶的高度 那么,作为连续内存类型的堆栈应该怎么设计呢?大家可以自己先试一下: (1)设计堆栈节点 [cpp] view plain copy typedef struct _STACK_NODE { int* pData; int length;

JavaScript js调用堆栈(二)

本文主要介绍JavaScript的内存空间 var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 首先需要对栈(stack),堆(heap),与队列(queue)有一定的了解: 栈(stack) 这种乒乓球的存放方式与栈中存取数据的方式如出一辙.处于盒子中最顶层的乒乓球5,它一定是最后被放进去,但可以最先被使用.而我们想要使用底层的乒乓球1,就必须将上面的4个乒乓球取出来,让乒乓球1处于盒子顶层.这就是栈空间先进后出,后进先出的特点

函数的工作原理——划分RAM搞不懂啊???

1.看到<21天学会C++>P92的函数工作原理之划分RAM,感觉还是迷迷糊糊,不太明白,进一步查询??? 2.程序启动时,操作系统(如DOS,Windows等)将依据编译器的需求设置各种内存区域. 对于一个C++程序员来说,经常需要关心的是全局名称空间.自由存储器.寄存器.代码空间和堆栈. 3.寄存器:CPU中的一个特殊存储区域,任意给定时刻指向下一行代码代码的寄存器组的寄存器被称为指令指针.指令指针的任务是跟踪接下来将执行哪一行代码. 4.代码空间:代码本身存放在代码空间中,每行代码都被转

C++ 对象模型详细讲解(特别容易理解)

c++对象模型系列 转 一.指针与引用 一 概括 指针和引用,在C++的软件开发中非常常见,如果能恰当的使用它们能够极大的提 高整个软件的效率,但是很多的C++学习者对它们的各种使用情况并不是都了解,这就导致了实际的软件开发中经常会内存泄漏,异常抛出,程序崩溃等问题.对 于C和C++的初学者,那更是被它们搞的迷迷糊糊.本篇作为[深入C++]系列的第一节,我们就带领大家把指针和引用这个基本功练好. 二 指针 指针,指针的定义是什么呢?好像要想给个直接的定义还是很难的哦,所以我们这里用它的语法结合图

Oracle ErrorStack 使用和阅读详解

一.概述 在Oracle数据库运行过程中,我们经常会遇到这样或那样的错误,但是错误的提示并不具体,加大了我们在诊断问题时的难度. ErrorStack是Oracle提供的一种对于错误堆栈进行跟踪的方法,通过设置跟踪可以将一些指定错误的后台信息详细的转储出来,写入跟踪文件,帮助我们诊断问题. 备注: 1.当oracle发生关键的错误诸如:ora-600,Errorstack是自动被oracle dump写入trace文件中. 2.当你在alert.log里面看见这类错误,并提示已经产生trace文