c语言堆和栈的区别

Python019

c语言堆和栈的区别,第1张

内存分配中的堆和栈

在 C 语言中,内存分配方式不外乎有如下三种形式:

从静态存储区域分配:它是由编译器自动分配和释放的,即内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,直到整个程序运行结束时才被释放,如全局变量与 static 变量。

在栈上分配:它同样也是由编译器自动分配和释放的,即在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元将被自动释放。需要注意的是,栈内存分配运算内置于处理器的指令集中,它的运行效率一般很高,但是分配的内存容量有限。

从堆上分配:也被称为动态内存分配,它是由程序员手动完成申请和释放的。即程序在运行的时候由程序员使用内存分配函数(如 malloc 函数)来申请任意多少的内存,使用完之后再由程序员自己负责使用内存释放函数(如 free 函数)来释放内存。也就是说,动态内存的整个生存期是由程序员自己决定的,使用非常灵活。需要注意的是,如果在堆上分配了内存空间,就必须及时释放它,否则将会导致运行的程序出现内存泄漏等错误。

数据结构的堆和栈

在数据结构中,栈是一种可以实现“先进后出”(或者称为“后进先出”)的存储结构。假设给定栈 S=(a0,a1,…,an-1),则称 a0 为栈底,an-1 为栈顶。进栈则按照 a0,a1,…,an-1 的顺序进行进栈;而出栈的顺序则需要反过来,按照“后存放的先取,先存放的后取”的原则进行,则 an-1 先退出栈,然后 an-2 才能够退出,最后再退出 a0。

在实际编程中,可以通过两种方式来实现:使用数组的形式来实现栈,这种栈也称为静态栈;使用链表的形式来实现栈,这种栈也称为动态栈。

相对于栈的“先进后出”特性,堆则是一种经过排序的树形数据结构,常用来实现优先队列等。假设有一个集合 K={k0,k1,…,kn-1},把它的所有元素按完全二叉树的顺序存放在一个数组中,并且满足:

则称这个集合 K 为最小堆(或者最大堆)。

由此可见,堆是一种特殊的完全二叉树。其中,节点是从左到右填满的,并且最后一层的树叶都在最左边(即如果一个节点没有左儿子,那么它一定没有右儿子);每个节点的值都小于(或者都大于)其子节点的值。

/*

下面的代码定义了一些宏,使用这些宏能为多种数据类型建立同种逻辑的相关数据结构和算法。

使用这些宏,例子代码定义了3种数据类型的相关内容。

我在代码中都是ARRAY、数组的叫法,但是你把名字改成堆栈就可以了,因为堆栈的基本操作都有了。大小也会自动变大在需要的时候。

泛型宏的类型参数应该是个合法的符号名,例如:int,double等,

如果类型中包含特别的字符,可以先typedef一下,例如:typedef int *INT_PTR

这样就可以用INT_PTR表示原始的int*类型了。注意不能用宏,因为展开后还是包含

特别字符。

*/

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

#include <malloc.h>

#include <stddef.h>

/*避免符号重复的前缀*/

#define GENERIC_PREFIX() __C_Generic_2007_10_16_

/*一个宏,用于产生(针对某种包含数据类型的泛型数组)的类型名*/

#define ARRAY_TYPE(T) GENERIC_PREFIX()Array_##T

/*一些宏,用于(针对某种包含数据类型的泛型数组)的操作*/

#define ARRAY_NEW(T,N) ARRAY_TYPE(T)_New(N) /*创建新的元素为T的数组,初始容量为N*/

#define ARRAY_FREE(T,A) ARRAY_TYPE(T)_Free(&(A))/*释放元素为T的数组A*/

#define ARRAY_ITEM(T,A,N) (*ARRAY_TYPE(T)_Item(&(A),N)) /*获取元素为T的数组A的第N个元素*/

#define ARRAY_FRONT(T,A) (*ARRAY_TYPE(T)_Item(&(A),0)) /*获取元素为T的数组A的第一个(顶部)元素*/

#define ARRAY_BACK(T,A) (*ARRAY_TYPE(T)_Item(&(A),(A).size-1)) /*获取元素为T的数组A的末尾(底部)元素*/

#define ARRAY_RESERVE(T,A,N) ARRAY_TYPE(T)_Reserve(&(A),N) /*为元素为T的数组A保留至少N的容量*/

#define ARRAY_RESIZE(T,A,N) ARRAY_TYPE(T)_Resize(&(A),N) /*设置元素为T的数组A的大小为N(含有N各元素)*/

#define ARRAY_PUSH_BACK(T,A,V) ARRAY_TYPE(T)_PushBack(&(A),V) /*在元素为T的数组A的末尾压入一个元素V*/

#define ARRAY_POP_BACK(T,A) ARRAY_TYPE(T)_PopBack(&(A)) /*在元素为T的数组A的末尾弹出一个元素*/

#define ARRAY_PUSH_FRONT(T,A,V) ARRAY_TYPE(T)_Insert(&(A),0,V) /*在元素为T的数组A的头部压入一个元素V*/

#define ARRAY_POP_FRONT(T,A) ARRAY_TYPE(T)_Remove(&(A),0) /*在元素为T的数组A的头部弹出一个元素*/

#define ARRAY_INSERT(T,A,I,V) ARRAY_TYPE(T)_Insert(&(A),I,V) /*在元素为T的数组A的I处插入一个元素V*/

#define ARRAY_REMOVE(T,A,I) ARRAY_TYPE(T)_Remove(&(A),I) /*在元素为T的数组A的I处移除一个元素*/

/*一个宏,定义包含某种数据的泛型数组的数据结构及相应算法*/

#define ARRAY_DEF(T) \

typedef struct ARRAY_TYPE(T)_tag \

{ \

T (*const data) /*数据*/\

size_t const capacity/*容量*/\

size_t const size /*大小*/\

}ARRAY_TYPE(T)\

\

/*创建新的元素为T的数组,初始容量为N*/ \

__inline ARRAY_TYPE(T) ARRAY_TYPE(T)_New(size_t initCap) \

{ \

ARRAY_TYPE(T) r\

*(T (**))(void**)(&r)=(T (*))malloc(sizeof(T)*initCap)\

assert(r.data!=NULL)\

*(size_t*)((void**)(&r)+1)=initCap\

*((size_t*)((void**)(&r)+1)+1)=0\

return r\

}\

\

/*释放元素为T的数组A*/ \

__inline void ARRAY_TYPE(T)_Free(ARRAY_TYPE(T) const *a) \

{ \

assert(a->data!=NULL)\

free(a->data)\

}\

\

/*获取元素为T的数组A的第N个元素*/ \

__inline T * ARRAY_TYPE(T)_Item(ARRAY_TYPE(T) const *a, size_t index) \

{ \

assert(index>=0 &&index<(a->size))\

return a->data+index\

}\

\

/*为元素为T的数组A保留至少N的容量*/ \

__inline void ARRAY_TYPE(T)_Reserve(ARRAY_TYPE(T) const *a,size_t cap) \

{ \

if (a->capacity<cap) \

{ \

(*((T const **)(void const **)a))=realloc(a->data, (cap*4/3)*sizeof(T))\

assert(a->data!=NULL)\

*(size_t*)((void**)(a)+1)=cap\

} \

}\

\

/*设置元素为T的数组A的大小为N(含有N各元素)*/ \

__inline void ARRAY_TYPE(T)_Resize(ARRAY_TYPE(T) const *a,size_t sz) \

{ \

if (a->size<=sz) \

{ \

*((size_t*)((void**)(a)+1)+1)=sz\

} \

else \

{ \

ARRAY_TYPE(T)_Reserve(a,sz)\

*((size_t*)((void**)(a)+1)+1)=sz\

} \

}\

\

/*在元素为T的数组A的末尾压入一个元素V*/ \

__inline void ARRAY_TYPE(T)_PushBack(ARRAY_TYPE(T) const *a,T const vp) \

{ \

ARRAY_TYPE(T)_Reserve(a,a->size+1)\

a->data[a->size]=vp\

(*((size_t*)((void**)(a)+1)+1))++\

}\

\

/*在元素为T的数组A的末尾弹出一个元素*/ \

__inline void ARRAY_TYPE(T)_PopBack(ARRAY_TYPE(T) const *a) \

{ \

assert(a->size>0)\

(*((size_t*)((void**)(a)+1)+1))--\

}\

\

/*在元素为T的数组A的I处插入一个元素V*/ \

__inline void ARRAY_TYPE(T)_Insert(ARRAY_TYPE(T) const *a,size_t index,T const vp) \

{ \

size_t i\

assert(index>=0 &&index<=(a->size))\

ARRAY_TYPE(T)_Reserve(a,a->size+1)\

for (i=a->sizei>indexi--) \

{ \

a->data[i]=a->data[i-1]\

} \

a->data[index]=vp\

(*((size_t*)((void**)(a)+1)+1))++\

}\

\

/*在元素为T的数组A的I处移除一个元素*/ \

__inline void ARRAY_TYPE(T)_Remove(ARRAY_TYPE(T) const *a,size_t index) \

{ \

assert(index>=0 &&index<(a->size))\

for (index++(a->size)>indexindex++) \

{ \

a->data[index-1]=a->data[index]\

} \

(*((size_t*)((void**)(a)+1)+1))--\

}

/*定义一种存放long的数组*/

ARRAY_DEF(long)

/*定义一种存放char的数组*/

ARRAY_DEF(char)

/*定义一种存放double的数组*/

ARRAY_DEF(double)

/*不能重复定义相同的类型*/

int main()

{

/*声明3个数组*/

ARRAY_TYPE(long) la=ARRAY_NEW(long,11)

ARRAY_TYPE(char) ca=ARRAY_NEW(char,1)

ARRAY_TYPE(double) da=ARRAY_NEW(double,1)

/*压栈*/

ARRAY_PUSH_BACK(long,la,1)

/*打印大小(包含元素个数)*/

printf("size:%d\n",la.size)

/*打印容量(当前数组空间的大小)*/

printf("capacity:%d\n",la.capacity)

ARRAY_PUSH_BACK(long,la,2)

ARRAY_PUSH_BACK(long,la,3)

printf("size:%d\n",la.size)

printf("capacity:%d\n",la.capacity)

/*最深的那个元素*/

printf("%d\n",ARRAY_FRONT(long,la))

/*最浅的那个元素*/

printf("%d\n",ARRAY_BACK(long,la))

/*出栈*/

ARRAY_POP_BACK(long,la)

printf("size:%d\n",la.size)

printf("capacity:%d\n",la.capacity)

printf("%d\n",ARRAY_BACK(long,la))

printf("----------------------------\n")

ARRAY_PUSH_BACK(char,ca,'A')

printf("size:%d\n",ca.size)

printf("capacity:%d\n",ca.capacity)

ARRAY_PUSH_BACK(char,ca,'B')

ARRAY_PUSH_BACK(char,ca,'C')

printf("size:%d\n",ca.size)

printf("capacity:%d\n",ca.capacity)

printf("%c\n",ARRAY_FRONT(char,ca))

printf("%c\n",ARRAY_BACK(char,ca))

ARRAY_POP_BACK(char,ca)

printf("size:%d\n",ca.size)

printf("capacity:%d\n",ca.capacity)

printf("%c\n",ARRAY_BACK(char,ca))

printf("----------------------------\n")

ARRAY_PUSH_BACK(double,da,1.0)

printf("size:%d\n",da.size)

printf("capacity:%d\n",da.capacity)

ARRAY_PUSH_BACK(double,da,2.0)

ARRAY_PUSH_BACK(double,da,3.0)

printf("size:%d\n",da.size)

printf("capacity:%d\n",da.capacity)

printf("%f\n",ARRAY_FRONT(double,da))

printf("%f\n",ARRAY_BACK(double,da))

ARRAY_POP_BACK(double,da)

printf("size:%d\n",da.size)

printf("capacity:%d\n",da.capacity)

printf("%f\n",ARRAY_BACK(double,da))

ARRAY_FREE(double,da)

ARRAY_FREE(char,ca)

ARRAY_FREE(long,la)

return 0

}