浅析C语言中堆和栈的区别

在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到。但对于很多的初学着来说,堆栈是一个很模糊的概念。

堆栈:一种数据结构、一个在程序运行时用于存放的地方,这可能是很多初学者的认识,因为我曾经就是这么想的和汇编语言中的堆栈一词混为一谈。我身边的一些编程的朋友以及在网上看帖遇到的朋友中有好多也说不清堆栈,所以我想有必要给大家分享一下我对堆栈的看法,有说的不对的地方请朋友们不吝赐教,这对于大家学习会有很大帮助。

一.前言:

C语言程序经过编译连接后形成编译、连接后形成的二进制映像文件由栈,堆,数据段(由三部分部分组成:只读数据段,已经初始化读写数据段,未初始化数据段即BBS)和代码段组成,如下图所示:

1.栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。

2.堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。注堆和数据结构中的堆栈不一样,其类是与链表。

3.程序代码区:存放函数体的二进制代码。

4.数据段:由三部分组成:

1>只读数据段:

只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。一般是const修饰的变量以及程序中使用的文字常量一般会存放在只读数据段中。

2>已初始化的读写数据段:

已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并且有初值,以供程序运行时读写。在程序中一般为已经初始化的全局变量,已经初始化的静态局部变量(static修饰的已经初始化的变量)

3>未初始化段(BSS):

未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。与读写数据段类似,它也属于静态数据区。但是该段中数据没有经过初始化。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。在程序中一般是没有初始化的全局变量和没有初始化的静态局部变量。

二.堆和栈的区别

1.申请方式

(1)栈(satck):由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。

(2)堆(heap):需程序员自己申请(调用malloc,realloc,calloc),并指明大小,并由程序员进行释放。容易产生memory leak.

eg:char  p;

p = (char *)malloc(sizeof(char));

但是,p本身是在栈中。

2.申请大小的限制

(1)栈:在windows下栈是向底地址扩展的数据结构,是一块连续的内存区域(它的生长方向与内存的生长方向相反)。栈的大小是固定的。如果申请的空间超过栈的剩余空间时,将提示overflow。

(2)堆:堆是高地址扩展的数据结构(它的生长方向与内存的生长方向相同),是不连续的内存区域。这是由于系统使用链表来存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由底地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。

3.系统响应:

(1)栈:只要栈的空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

(2)堆:首先应该知道操作系统有一个记录空闲内存地址的链表,但系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的free语句才能正确的释放本内存空间。另外,找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

说明:对于堆来讲,对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,

4.申请效率

(1)栈由系统自动分配,速度快。但程序员是无法控制的

(2)堆是由malloc分配的内存,一般速度比较慢,而且容易产生碎片,不过用起来最方便。

5.堆和栈中的存储内容

(1)栈:在函数调用时,第一个进栈的主函数中后的下一条语句的地址,然后是函数的各个参数,参数是从右往左入栈的,然后是函数中的局部变量。注:静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续执行。

(2)堆:一般是在堆的头部用一个字节存放堆的大小。

6.存取效率

(1)堆:char *s1=”hellow tigerjibo”;是在编译是就确定的

(2)栈:char s1[]=”hellow tigerjibo”;是在运行时赋值的;用数组比用指针速度更快一些,指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上读取。

补充:

栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

7.分配方式:

(1)堆都是动态分配的,没有静态分配的堆。

(2)栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的。它的动态分配是由编译器进行释放,无需手工实现。

(0)

相关推荐

  • 深入浅析C语言中堆栈和队列

    1.堆和栈 (1)数据结构的堆和栈 堆栈是两种数据结构. 栈(栈像装数据的桶或箱子):是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取.这就如同要取出放在箱子里面底下的东西(放入的比较早的物体),首先要移开压在它上面的物体(放入的比较晚的物体). 堆(堆像一棵倒过来的树):是一种经过排序的树形数据结构,每个结点都有一个值.通常所说的堆的数据结构,是指二叉堆.堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆.由于堆的这个特性,常用来实现优先队列,堆的存取是随意,

  • 如何用C语言、Python实现栈及典型应用

    前言 栈是什么,你可以理解为一种先入后出的数据结构(First In Last Out),一种操作受限的线性表... C实现 借助与C语言中的void指针及函数指针,我们可以实现一个链式通用栈: /* stack.h */ #ifndef _STACK_H_ #define _STACK_H_ typedef struct stackNode { void *value; struct stackNode *next; } stackNode; typedef struct stack { st

  • C语言栈顺序结构实现代码

    复制代码 代码如下: /*** @brief C语言实现的顺序结构类型的栈* @author wid* @date 2013-10-29** @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!*/ #include <stdio.h>#include <stdlib.h>#include <string.h> #define TRUE 1#define FALSE 0 typedef struct Point2D{    int x;    int y;

  • c语言stack(栈)和heap(堆)的使用详解

    一.预备知识-程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)-由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.2.堆区(heap)-一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收.注意它与数据结构中的堆是两回事,分配方式倒是类似于链表.3.全局区(静态区)(static)-全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另

  • C语言实现颠倒栈的方法

    本文实例讲述了C语言实现颠倒栈的方法,很实用的技巧.分享给大家供大家参考之用. 具体实现方法如下: #include <iostream> #include <iterator> #include <algorithm> #include <vector> #include <stack> using namespace std; void initializeStack(stack<int> &st) { for(int i

  • C语言堆栈入门指南

    C语言堆栈入门指南 在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到.但对于很多的初学着来说,堆栈是一个很模糊的概念.堆栈:一种数据结构.一个在程序运行时用于存放的地方,这可能是很多初学者的认识,因为我曾经就是这么想的和汇编语言中的堆栈一词混为一谈.我身边的一些编程的朋友以及在网上看帖遇到的朋友中有好多也说不清堆栈,所以我想有必要给大家分享一下我对堆栈的看法,有说的不对的地方请朋友们不吝赐教,这对于大家学习会有很大帮助. 首先在数据结构上要知道堆栈,尽管我们这么称呼它,

  • 浅谈C语言函数调用参数压栈的相关问题

    参数入栈的顺序 以前在面试中被人问到这样的问题,函数调用的时候,参数入栈的顺序是从左向右,还是从右向左.参数的入栈顺序主要看调用方式,一般来说,__cdecl 和__stdcall 都是参数从右到左入栈. 看下面的代码: #include <stdio.h> int test(int a, int b) { printf("address of a %x.\n", &a); printf("address of b %x.\n", &b)

  • C语言 栈的表示和实现详细介绍

    C语言 栈的表示和实现详细介绍 定义:栈是限定仅在表尾进行插入和删除操作的线性表. 栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表.它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来).栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针. 栈是允许在同一端进行插入和删除操作的特殊线性表.允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom):栈底固定,而栈顶浮动:

  • C语言 数据结构中栈的实现代码

    数据结构中的栈是什么 举一个简单的例子:在往箱子里面放衣物的时候,放在最上面的衣物总是我们最后放上去的:而当我们从箱子里取出衣物的时候,总是最先拿出上面的.这就是现实生活中的栈. 准确的讲,栈就是一种可以实现"先进后出(或者叫后进先出)"的存储结构. 学过数据结构的人都知道:栈可以用两种方式来实现,一种方法是用数组实现栈,这种栈成为静态栈:另外一种方法是用链表实现栈,这种栈叫做动态栈. 栈中通常存放着程序的局部变量等.栈通常有出栈和入栈操作. 栈的结构 空栈的结构:[其实就是栈顶和栈顶

  • C语言对栈的实现基本操作

    c语言中栈是一种数据结构,后进先出,即最后进入栈的数据最先弹出.c语言中没有栈这种数据类型,需要自己编程构建.下面我们就一起来了解一下c语言中栈的基本操作. C语言对栈的实现基本操作,操作如下: #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <stdbool.h> typedef struct Node { int data; struct Node * pNext;

  • C语言栈的表示与实现实例详解

    1.基本概念: C语言的栈是指限定仅在表尾进行插入和删除操作的线性表. 栈作为C语言中一种常用的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表.它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来).栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针. 栈是允许在同一端进行插入和删除操作的特殊线性表.允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom):栈底固定,而栈顶浮动

  • C语言之栈和堆(Stack && Heap)的优缺点及其使用区别

    一.前言 直到现在,我们已经知道了我们如何声明常量类型,例如int,double,等等,还有复杂的例如数组和结构体等.我们声明他们有各种语言的语法,例如Matlab,Python等等.在C语言中,把这些变量放在栈内存中. 二.基础 1.栈 什么是栈,它是你的电脑内存的一个特别区域,它用来存储被每一个function(包括mian()方法)创建的临时变量.栈是FILO,就是先进后出原则的结构体,它密切的被CPU管理和充分利用.每次function声明一个新的变量,它就会被"推"到栈中.然

随机推荐