动态内存分配

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、~

posted @ 2016-11-16 20:23  zhengmengen  阅读(483)  评论(1)    收藏  举报