C C++语言变量声明内存分配
c语言malloc函数的用法

c语言malloc函数的用法C语言中的malloc函数是非常常用的一个动态内存分配函数,它可以在程序运行时动态地分配指定字节数的内存空间,并返回指向该内存空间的指针。
在本篇文章中,我们将详细介绍malloc函数的用法,从基本概念开始,逐步回答相关问题,以帮助读者更好地理解和使用malloc函数。
一、基本概念1. 什么是动态内存分配?在程序运行时,静态内存分配是在编译时为变量分配内存空间,而动态内存分配是在程序运行时根据需要动态分配内存空间。
动态内存分配允许我们根据实际需求在程序运行过程中分配和释放内存空间,更加灵活地管理内存。
2. 为什么需要动态内存分配?动态内存分配在以下情况下非常有用:- 不知道需要多少内存,需要根据运行时情况来决定分配内存的大小。
- 需要在函数间共享大量数据,而不希望通过函数参数传递数据。
- 需要在程序的生命周期内分配和释放内存空间。
3. 什么是malloc函数?malloc函数是C语言中的动态内存分配函数之一,它的原型定义在stdlib.h头文件中,函数声明如下:cvoid* malloc(size_t size);该函数接受一个size_t类型的参数,表示需要分配的字节数,返回一个void类型的指针,指向分配的内存空间的起始地址。
二、malloc函数的用法1. 如何使用malloc函数进行内存分配?使用malloc函数进行内存分配的步骤如下:- 包含头文件:在程序中使用malloc函数之前,需要包含stdlib.h头文件。
- 调用malloc函数:使用malloc函数时,需要传入一个size_t类型的参数,表示需要分配的字节数。
函数会在堆内存中分配指定大小的连续内存空间,并返回指向该内存空间的起始地址。
- 检查分配是否成功:由于malloc函数可能无法分配所需大小的内存空间,因此在使用分配得到的内存之前,需要检查返回的指针是否为NULL。
如果指针为NULL,表示分配失败;反之,表示分配成功。
C语言中变量的声明和定义

C语⾔中变量的声明和定义变量声明和变量定义变量定义:⽤于为变量分配存储空间,还可为变量指定初始值。
程序中,变量有且仅有⼀个定义。
变量声明:⽤于向程序表明变量的类型和名字。
定义也是声明,extern声明不是定义定义也是声明:当定义变量时我们声明了它的类型和名字。
extern声明不是定义:通过使⽤extern关键字声明变量名⽽不定义它。
[注意]变量在使⽤前就要被定义或者声明。
在⼀个程序中,变量只能定义⼀次,却可以声明多次。
定义分配存储空间,⽽声明不会。
C++程序通常由许多⽂件组成,为了让多个⽂件访问相同的变量,C++区分了声明和定义。
变量的定义(definition)⽤于为变量分配存储空间,还可以为变量指定初始值。
在程序中,变量有且仅有⼀个定义。
声明(declaration)⽤于向程序表明变量的类型和名字。
定义也是声明:当定义变量的时候我们声明了它的类型和名字。
可以通过使⽤extern声明变量名⽽不定义它。
不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern。
extern声明不是定义,也不分配存储空间。
事实上它只是说明变量定义在程序的其他地⽅。
程序中变量可以声明多次,但只能定义⼀次。
只有当声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。
初始化式必须要有存储空间来进⾏初始化。
如果声明有初始化式,那么它可被当作是定义,即使声明标记为extern。
任何在多⽂件中使⽤的变量都需要有与定义分离的声明。
在这种情况下,⼀个⽂件含有变量的定义,使⽤该变量的其他⽂件则包含该变量的声明(⽽不是定义)。
如何清晰的区分变量声明和定义extern通知编译器变量在其他地⽅被定义1.extern告诉编译器变量在其他地⽅定义了。
例如:extern int i;//声明,不是定义int i;//声明,也是定义,未初始化带有初始化式的声明必定式定义2.如果声明有初始化式,就被当作定义,即使前⾯加了extern。
c语言中malloc函数的用法

c语言中malloc函数的用法一、什么是malloc函数malloc函数是C语言中的一种动态内存分配函数。
它可以在程序运行时动态地分配内存空间,使程序具有更大的灵活性和可扩展性。
二、malloc函数的语法void *malloc(size_t size);其中,size_t是无符号整数类型,表示要分配的内存空间大小,单位为字节。
void *是指向void类型的指针,表示返回值为一个指向分配内存空间首地址的指针。
三、如何使用malloc函数1. 分配内存空间使用malloc函数可以在程序运行时动态地分配内存空间。
例如,下面的代码片段可以申请一个大小为10个整形变量大小(即40个字节)的连续内存空间,并将其首地址赋给指针变量p:int *p;p = (int *) malloc(10 * sizeof(int));其中,sizeof(int)表示一个整形变量所占用的字节数。
2. 释放内存空间在程序运行过程中,如果不再需要某个已经申请过的动态内存空间,则应该将其释放以便其他程序使用。
释放内存空间可以使用free函数。
例如:free(p);其中,p是之前申请过的动态内存空间首地址。
3. 检查是否成功分配了内存由于动态分配内存在运行时才进行,因此可能会出现分配内存失败的情况。
为了避免程序在使用未成功分配的内存空间时出现错误,应该在使用malloc函数后检查是否成功分配了内存空间。
例如:int *p;p = (int *) malloc(10 * sizeof(int));if(p == NULL){printf("Failed to allocate memory.");exit(1);}如果malloc函数返回值为NULL,则说明分配内存失败。
4. 动态调整已经申请过的内存空间大小有时候,我们需要动态地调整已经申请过的内存空间大小。
这可以使用realloc函数实现。
例如:int *p;p = (int *) malloc(10 * sizeof(int));// 假设我们需要将p指向的动态数组大小扩展到20个整形变量p = (int *) realloc(p, 20 * sizeof(int));其中,realloc函数第一个参数是之前申请过的动态内存空间首地址,第二个参数是要扩展到的新数组大小。
c语言中static变量详解

c语⾔中static变量详解Static翻译出来是“静态”“静⽌”的意思,在C语⾔中的意思其实和它的本意差不多,表⽰“静态”或者“全局”的意思,⽤来修饰变量和函数。
经static修饰过后的变量或者函数的作⽤域或者存储域会发⽣变化,⽽由static修饰的变量在初始值⽅⾯也会表现出static关键字的优势。
想知道经static修饰过后的变量或者函数的作⽤域或者存储域发⽣了什么变化吗,发⽣变化的原因是什么吗?请⼤家继续往下看!⼀、c程序的内存分布既然static是⽤来修饰变量和函数的,⽽变量和函数⼜是组成c程序必不可少的,C程序的内存分布图如下。
C程序由下⾯5部分组成: 1)正⽂段——CPU执⾏的机器指令部分;⼀个程序只有⼀个副本;只读,防⽌程序由于意外事故⽽修改⾃⾝指令; 2)初始化数据段(数据段)——在程序中所有赋了初值的全局变量,存放在这⾥。
3)⾮初始化数据段(bss段)——在程序中没有初始化的全局变量;内核将此段初始化为0。
4)栈——增长⽅向:⾃顶向下增长;⾃动变量以及每次函数调⽤时所需要保存的信息(返回地址;环境信息)。
5)堆——动态存储区。
是向⾼地址扩展的数据类型,是⾃下向上的扩展⽅式。
c程序内存分布图上⾯的C程序分布图很明显的告诉我们,变量是存储在栈区或者堆区或者bss段或者data段,变量的存储域为什么会有所不同呢?其实原因很简单,说⽩了就是与他们定义在程序的不同地⽅,有没有static关键字修饰有关啦,定义在不同的地⽅也说明了他们有着不同的作⽤域。
⼆、static修饰的变量1. 全局静态变量 在全局变量之前加上关键字static,全局变量就被定义成为⼀个全局静态变量。
1)内存中的位置:静态存储区(静态存储区在整个程序运⾏期间都存在) 2)初始化:未经初始化的全局静态变量会被程序⾃动初始化为0(⾃动对象的值是任意的,除⾮他被显⽰初始化) 3)作⽤域:全局静态变量在声明他的⽂件之外是不可见的。
c语言外部变量声明技巧 -回复

c语言外部变量声明技巧-回复C语言外部变量声明技巧在C语言中,外部变量是指在所有函数之外声明的变量,这些变量可以在程序的任何地方使用。
外部变量在程序的不同部分之间共享数据,因此在使用它们时需要一些特殊的声明技巧。
本文将逐步解释外部变量的声明以及如何正确使用它们。
一、什么是外部变量?在C语言中,有三种变量作用域:局部变量、全局变量和外部变量。
局部变量的作用域仅限于声明它的函数内部;全局变量的作用域从声明它的位置开始,到程序的末尾,可以在程序的任何地方使用;而外部变量与全局变量类似,也可以在程序的任何地方使用,但其作用域没有全局变量那么广泛,它仅限于当前文件。
二、外部变量的声明外部变量的声明需要使用关键字"extern"加以标识。
下面是一个示例:cextern int count;上述代码表明我们正在声明一个名为"count"的外部变量,类型为int。
这个声明表明,该变量在其他地方定义,在本文件中只是进行了声明,这意味着我们可以在本文件中使用该外部变量,而不需要在此处进行定义。
三、外部变量的定义定义外部变量的方式与全局变量的定义相同。
下面是一个示例:cint count;上述代码显示了如何定义一个名为"count"的外部变量,其类型为int。
这意味着我们正在为这个变量分配内存空间并初始化它。
四、使用外部变量在使用外部变量时,我们需要注意以下几点:1. 外部变量的作用域仅限于当前文件。
这意味着,如果我们在其他文件中声明了一个与当前文件中的外部变量同名的变量,那么它们不会相互干扰,它们是不同的变量。
2. 外部变量的声明与定义必须吻合。
这意味着,我们在声明外部变量时,必须使用相同的类型和变量名。
否则,会导致编译错误。
3. 外部变量的初始化只能在定义时进行。
这是因为外部变量的定义实际上是分配内存空间的过程,所以我们只能在定义它们时进行初始化。
五、使用头文件当我们在多个文件中使用外部变量时,为了方便管理和避免重复代码,我们可以使用头文件来声明外部变量。
C语言技术的使用方法解析及示范

C语言技术的使用方法解析及示范C语言作为一种高级编程语言,在计算机科学领域具有广泛的应用。
它的简洁性和高效性使得它成为许多程序员的首选语言。
本文将对C语言技术的使用方法进行解析,并通过示范来进一步说明。
一、C语言的基本语法和数据类型C语言的基本语法包括变量声明、赋值语句、条件语句、循环语句等。
变量声明用于定义变量的类型和名称,赋值语句用于给变量赋初值。
条件语句和循环语句则用于控制程序的执行流程。
C语言支持多种数据类型,包括整型、浮点型、字符型等。
整型可以存储整数值,浮点型可以存储小数值,字符型可以存储字符。
在声明变量时,需要指定变量的数据类型,以便在内存中分配相应的空间。
二、C语言的函数和库函数的使用函数是C语言程序的基本组成部分,它用于封装一段可重复使用的代码。
通过函数,可以将程序分割成多个模块,提高代码的可读性和可维护性。
C语言提供了许多库函数,可以方便地进行文件操作、字符串处理、数学计算等。
例如,stdio.h库函数提供了标准输入输出函数,可以实现从键盘读取输入和向屏幕输出;string.h库函数提供了字符串处理函数,可以实现字符串的拷贝、连接等操作。
三、C语言的指针和内存管理指针是C语言中的一个重要概念,它用于存储变量的内存地址。
通过指针,可以直接访问和修改变量的值,提高程序的效率。
在使用指针时,需要注意内存管理的问题。
C语言中没有自动垃圾回收机制,程序员需要手动分配和释放内存空间。
通过malloc()函数可以动态分配内存,通过free()函数可以释放内存。
四、C语言的结构体和文件操作结构体是一种用户自定义的数据类型,可以将多个不同类型的变量组合在一起,形成一个新的数据类型。
通过结构体,可以更好地组织和管理数据。
C语言提供了文件操作函数,可以实现文件的读写操作。
通过fopen()函数可以打开文件,通过fread()函数可以读取文件内容,通过fwrite()函数可以写入文件内容,通过fclose()函数可以关闭文件。
c语言存储数据的方式

c语言存储数据的方式C语言是一种广泛应用于计算机科学领域的编程语言,它提供了多种存储数据的方式。
本文将介绍几种常见的C语言数据存储方式,包括变量、数组、结构体、枚举和指针。
1. 变量变量是C语言中最基本的数据存储方式。
通过声明变量可以为不同类型的数据分配内存空间,并可以对其进行读取和修改。
常见的变量类型包括整型、浮点型、字符型等。
例如,可以使用int型变量来存储整数,float型变量来存储浮点数,char型变量来存储字符。
2. 数组数组是一种按顺序存储相同类型数据的集合。
通过声明数组可以在内存中分配一块连续的空间来存储数据。
数组的元素可以通过索引访问,索引从0开始。
例如,可以使用int型数组来存储一组整数,float型数组来存储一组浮点数,char型数组来存储一组字符。
3. 结构体结构体是一种自定义的数据类型,可以将多个不同类型的数据组合在一起。
通过声明结构体可以定义一个包含多个成员的数据结构,并可以为每个成员分配内存空间。
结构体的成员可以通过.运算符来访问。
例如,可以使用struct关键字定义一个学生结构体,包含姓名、年龄和成绩等成员。
4. 枚举枚举是一种自定义的数据类型,用于定义一组相关的常量。
通过声明枚举可以为每个常量分配一个整数值,并可以使用这些常量来表示特定的状态或选项。
例如,可以使用enum关键字定义一个颜色枚举,包含红、绿、蓝等常量。
5. 指针指针是一种特殊的变量,用于存储内存地址。
通过声明指针可以指向其他变量或数据结构的内存地址,并可以通过解引用操作符*来访问指针所指向的值。
指针在C语言中常用于动态内存分配和函数传参等场景。
例如,可以使用int型指针来存储一个整数变量的内存地址,char型指针来存储一个字符数组的内存地址。
总结起来,C语言提供了多种灵活的数据存储方式,包括变量、数组、结构体、枚举和指针。
合理选择不同的数据存储方式可以根据实际需求来提高程序的效率和可读性。
在实际编程中,根据数据类型和数据结构的特点,选择合适的存储方式是非常重要的。
C语言内存分配问题(整理)

我查了下资料,有说分四个,有说分五个加一个程序代码区,我没查到参考的专业书籍。所 以麻烦知道的告知一下,完善一下。
2、 内存分配方式 内存分配方式有三种:
1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整 个运行期间都存在。例如全局变量,static 变量。
4、动态分配释放内存举例 用 malloc 动态分配内存后一定要判断一下分配是否成功,判断指针的值是否为 NULL。 内存分配成功后要对内存单元进行初始化。 内存分配成功且初始化后使用时别越界了。 内存使用完后要用 free(p)释放,注意,释放后,p 的值是不会变的,仍然是一个地址值, 仍然指向那块内存区,只是这块内存区的值变成垃圾了。为了防止后面继续使用这块内存, 应在 free(p)后,立即 p=NULL,这样后面如果要使用,判断 p 是否为 NULL 时就会判断出 来。
NO.2
char *GetMemory(void) {
char Байду номын сангаас[] = hello world; retrun p; } void Test(void) { char *str = NULL; str = GetMemory(); printf(str); }
问题同 NO.1
NO.3
void GetMemory(char **p, int num) {
free(str); if(str != NULL) {
strcpy(str,"world"); printf(str); } }
问题同 NO.1 我对以上问题的分析:
NO.1:程序首先申请一个 char 类型的指针 str,并把 str 指向 NULL(即 str 里存的是 NULL 的地址,*str 为 NULL 中的值为0),调用函数的过程中做了如下动作: 1、申请一个 char 类型的指针 p, 2、把 str 的内容 copy 到了 p 里(这是参数传递过程中系统所做的), 3、为 p 指针申请了 100 个空间, 4、返回 Test 函数.最后程序把字符串 hello world 拷贝到 str 指向的内存空间里.到这里错 误出现了! str 的空间始终为 NULL 而并没有实际的空间.深刻理解函数调用的第 2 步,将不难发现问 题所在!(注意:传递的参数和消除的参数) NO.2:程序首先申请一个 char 类型的指针 str,并把 str 指向 NULL.调用函数的过程中做了 如下动作: 1申请一数组 p[]并将其赋值为 hello world(数组的空间大小为 12), 2返回数组名 p 付给 str 指针(即返回了数组的首地址). 那么这样就可以打印出字符串"hello world"了么?当然是不能的! 因为在函数调用的时候漏掉了最后一步.也就是在第2步 return 数组名后,函数调用还要 进行一步操作,也就是释放内存空间.当一个函数被调用结束后它会释放掉它里面所有的变 量所占用的空间.所以数组空间被释放掉了,也就是说 str 所指向的内容将不确定是什么东 西. NO.3:正确答案为可以打印出 hello.但内存泄漏了! 需要用 free()函数进行释放。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C/C++语言变量声明内存分配2010-11-08 07:10:20| 分类:编程|字号订阅一个由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/0"在常量区,p3在栈上。
static int c =0;//全局(静态)初始化区p1 = (char *)malloc(10);p2 = (char *)malloc(20);//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456/0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}===============C语言程序的内存分配方式1.内存分配方式内存分配方式有三种:[1]从静态存储区域分配。
内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。
例如全局变量,static变量。
[2]在栈上创建。
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
[3]从堆上分配,亦称动态内存分配。
程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。
动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。
2.程序的内存空间一个程序将操作系统分配给其运行的内存块分为4个区域,如下图所示。
一个由C/C++编译的程序占用的内存分为以下几个部分,1、栈区(stack)—由编译器自动分配释放,存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
其操作方式类似于数据结构中的栈。
2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
分配方式类似于链表。
3、全局区(静态区)(static)—存放全局变量、静态数据、常量。
程序结束后由系统释放。
4、文字常量区—常量字符串就是放在这里的。
程序结束后由系统释放。
5、程序代码区—存放函数体(类成员函数和全局函数)的二进制代码。
下面给出例子程序,int a = 0; //全局初始化区char *p1; //全局未初始化区int main() {int b; //栈char s[] = "abc"; //栈char *p2; //栈char *p3 = "123456"; //123456在常量区,p3在栈上。
static int c =0;//全局(静态)初始化区p1 = new char[10];p2 = new char[20];//分配得来得和字节的区域就在堆区。
strcpy(p1, "123456"); //123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}3.堆与栈的比较3.1申请方式stack: 由系统自动分配。
例如,声明在函数中一个局部变量int b; 系统自动在栈中为b开辟空间。
heap: 需要程序员自己申请,并指明大小,在C中malloc函数,C++中是new运算符。
如p1 = (char *)malloc(10); p1 = new char[10];如p2 = (char *)malloc(10); p2 = new char[20];但是注意p1、p2本身是在栈中的。
3.2申请后系统的响应栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。
对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。
由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
3.3申请大小的限制栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。
这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。
因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。
这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。
堆的大小受限于计算机系统中有效的虚拟内存。
由此可见,堆获得的空间比较灵活,也比较大。
3.4申请效率的比较栈由系统自动分配,速度较快。
但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是栈,而是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。
但是速度快,也最灵活。
3.5堆和栈中的存储内容栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。
注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。
堆中的具体内容有程序员安排。
3.6存取效率的比较char s1[] = "a";char *s2 = "b";a是在运行时刻赋值的;而b是在编译时就确定的;但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:int main(){char a = 1;char c[] = "1234567890";char *p ="1234567890";a = c[1];a = p[1];return 0;}对应的汇编代码10: a = c[1];00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]0040106A 88 4D FC mov byte ptr [ebp-4],cl11: a = p[1];0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]00401070 8A 42 01 mov al,byte ptr [edx+1]00401073 88 45 FC mov byte ptr [ebp-4],al第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,再根据edx读取字符,显然慢了。
3.7小结堆和栈的主要区别由以下几点:1、管理方式不同;2、空间大小不同;3、能否产生碎片不同;4、生长方向不同;5、分配方式不同;6、分配效率不同;管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。
但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M。
当然,这个值可以修改。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。
对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构。
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
分配方式:堆都是动态分配的,没有静态分配的堆。
栈有2种分配方式:静态分配和动态分配。
静态分配是编译器完成的,比如局部变量的分配。
动态分配由malloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。
显然,堆的效率比栈要低得多。
从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。
所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。