- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
heap
stack 系 统 自 动 管 理
Data seg
Static变量(静态变量,全局变量)运行相同程序的每 个进程,有自己的数据段。
code
可执行指令放在代码段中,任何时刻,内存中只有 一份相同程序的指令拷贝,多个实例共享这些代码。
动态内存分配
C标准函数库提供了许多函数来实现对堆上 内存(动态内存)的管理(stdlib.h):
malloc函数可以从堆上获得指定字节数的内存空 间,其函数声明如下:
void * malloc(int n);
• void *:空类型指针,表示不指定是指向哪一种类型数据的指 针变量,使用时要进行强制类型转换
• 其中形参n为要求分配的字节数。如果函数执行成功 ,malloc函数返回获得的内存空间的首地址;如果 函数执行失败,那么返回值为NULL。由于malloc函 数值的类型为void型指针,因此可以将其值类型转 换后赋值给任意类型指针,这样就可以通过操作该 类型指针来操作从堆上获得的内存空间。
realloc函数
realloc函数的功能比malloc函数和calloc函数 更为丰富,可实现内存分配和内存释放的 功能。其函数声明如下:
void *realloc(void *p, int n);
其中,指针p必须为指向堆内存空间的指针,即由 malloc函数、calloc函数或realloc函数分配空间的指针。 realloc函数将指针p指向的内存块的大小改变为n字节。 如果n小于或等于p之前指向的空间大小,那么保持原 有状态不变。如果n大于原来p之前指向的空间大小, 那么系统将重新为p从堆上分配一块大小为n的内存空 间,同时将p原来指向空间的内容依次复制到新的内存 空间上,p之前指向的空间被释放。realloc分配的空间 也是未初始化的。
元素类型名 * point = NULL; point = (元素类型名 *) malloc (数组容量 * sizeof(元素类 型名)); 或使用calloc,代码如下: 元素类型名 * point = NULL; point = (元素类型名 *) calloc (数组容量, sizeof(元素类 型名));
上述语句将指针point赋值为一块堆上的内 存空间的首地址,之后就可以像操作数组 一样来操作这块内存空间。例如,p[i]就可 以取到该内存空间上第i个(从0开始计数) 字节长度为sizeof(元素类型名)的内存上的 值。需要注意的是,由于动态数组是从堆 上获取的内存空间,因此在程序结束时, 必须要手动释放内存。
free函数可以实现释放内存的功能:
void free(void * p);
• 由于形参为void指针,free函数可以接受任意类型的 指针实参。例如:
char * p1 = NULL; int * p2 = NULL; … free(p1); free(p2);
• 但是,free函数只释放指针指向的内容,而该指针的 值仍然指向原来指向的地方,此时指针为野指针, 如果此时操作该指针会导致不可预期的错误。安全 的做法是:在使用free函数释放指针指向的空间之后 ,将指针值置为NULL。因此,对于前例,需要在 return语句前加入以下两行语句:
借助堆管理来实现动态数组的基本思想就是动态 地按需分配。要求多少内存就分配多少内存,根 据需求,使用分配函数在堆上获取指定大小的内 存空间,最后将这块内存空间的起始地址作为该 数组的首地址。使用指针变量从堆上动态分配空 间的方法可以模拟实现动态数组,即可在运行期 设定数组容量的数组。其基本代码步骤如下:
分配内存:malloc函数、calloc函数和realloc函 数 释放内存:free函数
堆内存必须自己调用内存分配函数申请, 不需要了必须自己调用内存释放函数释放 。
malloc函数
int *p = (int*)malloc(20);//动态在 堆区分配空间,(空间内容初始 值为随机值)必须人为释放
堆管理
需要掌握以下知识点:
理解堆的概念;
malloc函数和free函数的正确使用; memset函数的正确使用; calloc函数和realloc函数的正确使用; 动态数组的管理和使用。
引言
前面的数组大小是固定的,如何根据实际情况动态生成呢 ?需要的时候才占有物理空间,不需要的时候就可以清除 ,从而充分节约宝贵的内存资源---动态数组 指针其实就是可变数组的首地址,说是可变数组,是指其 包含内容的数量的可变的
释放内存步骤
1.调用函数free()释放掉空间 注意:
1.不可以使用free()掉后的空间 2.free()后,最好将指针置为NULL,因为如果 不做这步处理,原来的指针依旧指向刚才释放 的空间,可以继续操作 3.避免重复释放空间
free(p); p = NULL
动态数组的实现
C语言的内建数组属于静态数组,程序运行 前就必须确定其数组容量。但是,有的数 组需要的容量在程序运行后才会知道;对 于这些数组,如果使用静态数组只能为其 预先设定一个足够大的数组容量,因此造 成内存空间的浪费。
int * p = NULL; /* p也可以为其他类型指针 */ p = (int *) malloc (sizeof(int)); if (NULL == p) printf(“Can’t get memory!\n”); memset(p, 0, sizeof(int));
wenku.baidu.com
free函数
从堆上获得的内存空间在程序结束后,系 统不会自动将其释放,需要程序员自己来 管理。一个程序结束时,必须保证所有从 堆上获得的空间已被安全释放,否则会导 致内存泻泄露。例如前例就会发生内存泄 露。如何避免内存泄露是堆内存管理的一 个重点和难点。
free(p); p = NULL;
calloc函数
calloc函数的功能与malloc函数相似,都从 堆上分配内存。其函数声明如下:
void *calloc(int n, int size); 函数返回值为void型指针。如果执行成功,函 数从堆上获得size×n的字节空间,并返回该空 间的首地址。如果执行失败,函数返回NULL 。该函数与malloc函数一个显著的不同是, calloc函数得到的内存空间是经过初始化的,其 内容为全0。calloc函数适合为数组申请空间, 可以将size设置为数组元素的空间长度,将n设 置为数组容量。
如果执行成功,realloc函数返回新空间的首地 址。如果失败,则返回NULL。当p的值为 NULL时,即realloc(NULL, n),其等效于 malloc(n);当n的值为0时,即realloc(p, 0),其 等效于free(p)。
注意
使用malloc函数、calloc函数和realloc函数分配的 内存空间都要使用free函数或指针参数为NULL的 realloc函数来释放。
分配内存的步骤:
1.申明一个指定类型的指针 2.计算要分配空间的大小,一般使用函数sizeof() 来实现 int * p = NULL; 3.调用函数 malloc() p = (int *) 完成空间的申请,将函数的返 malloc (sizeof(int)); 回值赋给指针变量, if (NULL == p) { 4.检查返回值是否不为 NULL ,保证空间分配成功 printf(“Can’t get memory! \n”); 5.分配好的空间是没有经过初始化的,其中可能 exit(); 包含一些垃圾信息,因此 } memset(p, 0, sizeof(int)); 调用函数memset() 将其用 0来填充是个好的习惯
memset函数
需要注意的是,malloc函数分配的内存空间 是未初始化的。因此,一般在使用该内存 空间时,要调用另一个函数memset来将其 初始化为全0。memset函数的函数声明如下 :
void * memset(void * p, int c, int n); 该函数可以将内存空间按字节为单位置为指定 的字符c。其中,p为要清零的内存空间的首地 址,c为要设定的值,n为被操作的内存空间的 字节长度。如果要使用memset清0,变量c的实 参要为0。
#include <stdio.h> #include <stdlib.h> float *getArray( int n) { void * p = NULL; if(n > 0) { p = malloc(n * sizeof(float)); if (NULL != p) memset(p, 0, sizeof(float)*n); } return p; } main() { float *p = getArray(10); free(p); }
以下程序中给指针p分配三个 double型动态内存单元,请填空。 # include <stdlib.h> main ( ) { double *p; p=(double *) malloc( ); p[0]=1.5;p[1]=2.5;p[2]=3.5; printf("%f%f%f\n",p[0],p[1],p[2]); free(p); }
进程的数据内存分配 程 序 员 管 理
堆,动态内存来自于堆,即:可随时通过malloc得到 空间,但必须用free函数释放。通常情况下,堆是向 上增长的,即:后面分配的地址比前面的地址在数 值上大一些。 栈,分配局部变量的地方,函数参数、函数的返回值和 返回地址也放在栈空间中,需要特别注意的是,当函数 返回后,存储在栈空间中的函数变量“自动消失”,空 间被其他函数使用。栈空间是向下增长的。