动态内存分配
1、内存分配方案
基于程序运行之前内存是否已经分配完毕,将内存分配策略分为:静态内存分配和动态内存分配。
基于位置的内存分配方式:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多
2、malloc和free
两个函数分别执行动态内存分配和释放(共同维护一个可用内存池)。当一个程序另需内存时,他就调用malloc函数,malloc从内存池中提取一块合适的内存,并返回一个指向这块内存的指针(malloc并不初始化该段内存)。当内存富余时,可调用free函数把多余的内存归还给内存池。
malloc分配的内存地址始终符合边界对齐要求。
#include<stdlib.h> //malloc和free都在该头文件中 #include<stdio.h> ... //malloc分配内存 int *pi1,pi2; pi1=malloc(100); //malloc函数返回一个指向所分配内存块的指针,大小为100个字节 pi2=malloc(25*sizeof(int)); //更优解,在不同计算机中,一个整数所需字节数可能有所不同,使用该种方法便于程序的移植 if(pi1==NULL||pi2==NULL){ //符号NULL定义于<stdio.h>中 printf("超出内存!\n"); exit(1); } //使用该内存 int *pi3; pi3=pi2; //保护原指针pi2 for(int i=0;i<25;i+=1){ *pi3++=0; //初始化为0 } for(int i=0;i<25;i+=1){ pi2[i]=1; //再利用 array[i] 与 *(array+(i)) 等价,将该内存块初始化为1 } //释放内存 for(int i=0;i<25;i+=1,pi1+=1,pi2+=1,pi3+=1){ //free必须配合循环使用,而且free()的参数只能是NULL或者malloc、calloc、realloc返回的值,为NULL时不会产生任何效果 free(pi1); free(pi2); free(pi3); } ...详见 http://www.cnblogs.com/hanyonglu/archive/2011/04/28/2031271.html
3、calloc和realloc
3.1 void *calloc(size_t num_elements,size_t element_size)
动态分配内存,在返回内存的指针之前先将内存初始化为0。
3.2 void realloc(void *ptr,size_t new_size)
用于修改原先已经分配的内存的大小(扩大或缩小)。ptr等于NULL时,realloc等价于malloc.
realloc的工作原理:尽量在原内存的基础上进行扩充或缩减,当原内存块的大小无法改变时:复制原内存块内容到新内存地址上。realloc之后,不能再使用原内存地址,而是应该使用realloc()返回的新的内存地址。
动态分配的内存必须整块一起释放,释放一块内存的一部分是不被允许的。但是使用realloc()可以缩减内存,有效地释放原内存尾部的部分内存(仅当原内存不允许修改大小时,才会“另辟蹊径”)。
4、内存泄漏
分配内存后,若在使用完之后不释放,将引起内存泄漏(Memory leak),内存泄漏最终将导致内存池中无内存可用,只能通过重启系统摆脱这种困境。
5、内存分配实例
/* **读取、排序和打印一列整数值 */ #include<stdlib.h> #include<stdio.h> //#define FAILURE_ERR EXIT_FAILURE; int compare_integers(void const*a,void const *b){ register int const *pa = a; register int const *pb = b; return *pa>*pb?1:*pa<*pb?-1:0; } int main(){ /* **变量声明 */ int *array; int num; int i; /* **确定变量个数 */ printf("how many integers are there?\n"); if(scanf("%d",&num)!=1){ printf("输入错误!"); exit(EXIT_FAILURE); } /* **分配内存 */ array =(int *)malloc(num*sizeof(int)); if(array==NULL){ printf("分配出错!"); exit(EXIT_FAILURE); } /* **读取数值 */ for(i=0;i<num;i+=1){ printf("?"); if(scanf("%d",array+i)!=1){ printf("ERROR reading value #%d\n",i); free(array); //array所指向的内存未变,仍然是数组开头。为什么这里的free不用循环?而且只是释放内存块的一部分? exit(EXIT_FAILURE); } } /* **排序 */ qsort(array,num,sizeof(int),compare_integers);
//void qort(void *array,int num,int width,int(*compare_integers)(const void*,const void*));
//qsort用于按照fun_name所定义的规则对指定数字进行排序C的库函数,其中排序规则fun_name()需要自己定义,如:
//int compare_integers(void const *a,void const *b){
// register int const *pa = a;
// register int const *pb = b;
// return *pa>*pb?1:*pa<*pb?-1:0;
/* **打印 */ for(i=0;i<num;i++) printf("%d\n",*array+i); /* **释放内存 */ free(array); printf("观察free%d",*array); printf("观察free%d",*array+2);//内存释放成功,array[2]中的值已为任意值 getchar(); return EXIT_SUCCESS; }
实例中的free没有配合循环,但经检验,却能成功实现所申请内存的全部释放。scanf用作获取键入值,其返回值为成功获取的值的个数。
EXIT_FAILURE和EXIT_SUCCESS均在stdlib.h中定义,分别代表程序返回的两种情况:失败、成功。(自定义的宏好像不能替代,编译器会有红线报错)
6、~

浙公网安备 33010602011771号