您的位置 首页 新品

C言语的那些小秘密之仓库

何为堆栈?首先要明确堆栈是两种数据结构。栈是硬件,堆是一种动态存储结构,但是它们俩个又是如何共存的呢?

  在解说仓库之前,咱们先要来说说其实咱们常说的仓库是两种数据结构。那么什么是堆什么又是栈呢?

  栈,是硬件。首要效果表现为一种数据结构,是只能在某一端刺进和删去的特别线性表。它依照后进先出的准则存储数据,先进入的数据被压入栈底,最终的数据在栈顶,需求读数据的时分从栈顶开端弹出数据(最终一个数据被第一个读出来)。栈是答应在同一端进行刺进和删去操作的特别线性表。答应进行刺进和删去操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶起浮;栈中元素个数为零时称为空栈。刺进一般称为进栈(PUSH),删去则称为退栈(POP)。 栈也称为先进后出表。栈能够用来在函数调用的时分存储断点,做递归时要用到栈!

  以上界说是在经典计算机科学中的解说。

  在计算机体系中,栈则是一个具有以上特点的动态内存区域。程序能够将数据压入栈中,也能够将数据从栈顶弹出。在i386机器中,栈顶由称为esp的寄存器进行定位。压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。

  栈在程序的运转中有着无足轻重的效果。最重要的是栈保存了一个函数调用时所需求的保护信息,这常常称之为仓库帧或许活动记载。仓库帧一般包含如下几方面的信息:

  1. 函数的回来地址和参数

  2. 暂时变量:包含函数的非静态局部变量以及编译器主动生成的其他暂时变量。

  堆,是一种动态存储结构,实际上便是数据段中的自在存储区,它是C言语中运用的一种称号,常常用于动态数据的存储分配。堆中存入一数据,总是以2字节的整数倍进行分配,地址向添加方向变化。堆能够不断进行分配直到没有堆空间停止,也能够随时进行开释、再分配,不存在次第问题。

  堆和栈在运用时相向成长,栈向上成长,即向小地址方向成长,而堆向下增加,即向大地址方向,其间剩下部分是自在空间。运用过程中要避免增加过度而导致掩盖。

  一般的程序咱们都是运用小内存形式。

  理解了堆和栈的概念之后咱们来看一个面试的c言语标题。代码要相关要求如下所示:

  #include

  using namespace std;

  void print()

  {

  //这儿进行打印arr数组,print禁绝传参数

  }

  int main()

  {

  int s=0;

  int ss=0;

  char *str="fdsafdsafdsafdsafdsafdsafdsa";

  char fdsa='f';

  char srt[8];

  int arr[]={32,43,3,567,987,21,56};//数值随即

  print();

  return 0;

  }

  刚刚一开端看到这个标题时,你可能有点发懵,心想可能在不传递参数的情况下打印arr数组的内容,可是看看咱们的标题就应该知道该题跟栈有联系,在做之前咱们先来回忆几个知识点。

  push操作先修正指针,后将信息入栈。

  ESP为仓库指针,栈顶有ESP寄存器来定位。压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。

  EBP是32位的BP,EBP是基址指针,EBP与BP的联系就像AX与AL、AH的联系相同。BP为基指针寄存器,用它课直接存取仓库中的数据,他的效果在调用函数时保存ESP,使函数结束时能够正确回来。

  c的默许函数压栈操作为:

  参数是从右向左压栈的,默许四字节对齐,函数里面界说的变量是默许对齐方法—-变量首地址是本身结构体里面最大规范数据类型字节的整数倍。

  咱们先来看看上面这段代码的汇编句子:

  //*******************************************start*********************************************//

  .file "push.c"

  .text

  .globl print

  .type print, @function

  print:

  pushl %ebp

  movl %esp, %ebp

  popl %ebp

  ret

  .size print, .-print

  .section .rodata

  .LC0:

  .string "fdsafdsafdsafdsafdsafdsafdsa"

  .text

  .globl main

  .type main, @function

  main:

  pushl %ebp

  movl %esp, %ebp

  andl $-16, %esp

  subl $64, %esp

  movl %gs:20, %eax

  movl %eax, 60(%esp)

  xorl %eax, %eax

  movl $0, 44(%esp)

  movl $0, 40(%esp)

  movl $.LC0, 36(%esp)

  movb $102, 51(%esp)

  movl $32, 8(%esp)

  movl $43, 12(%esp)

  movl $3, 16(%esp)

  movl $567, 20(%esp)

  movl $987, 24(%esp)

  movl $21, 28(%esp)

  movl $56, 32(%esp)

  call print

  movl $0, %eax

  movl 60(%esp), %edx

  xorl %gs:20, %edx

  je .L3

  call __stack_chk_fail

  .L3:

  leave

  ret

  .size main, .-main

  .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"

  .section .note.GNU-stack,"",@progbits

  //*******************************************end*********************************************//

  看看上面的汇编代码,咱们的要点放在赤色字体部分,在函数的最初部分都有这么两行代码:

 pushl %ebp —————————>保存上一个函数的栈底

  movl %esp, %ebp —————————>用来保存当时仓库指针的值

  ebp寄存当时函数栈低的地址,便是说ebp能够看做一个指针,指向栈顶,而其实栈顶寄存的数据便是上一个函数的ebp的值,即便是main函数的栈底。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/116834.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部