zoukankan      html  css  js  c++  java
  • C语言 内存管理精讲(malloc,calloc,free,relloc使用)

    calloc 可以代替 malloc + memset,但是 malloc + memset 代替不了 calloc,
    calloc 大块内存时,如果是从系统分配,就可以免了 memset 的操作,快很多。

    memset可以设任意数,calloc只能设0
    calloc表示申请count*size大小的内存
    malloc只有一个参数

     malloc
    函数原型: extern void *malloc(unsigned int num_bytes);
    函数描述: 分配长度为num_bytes字节的内存块
    入口参数: num_bytes    内存块的大小(单位为字节)
    出口参数: 无(或为空)
    返回值:    如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
    函数说明    不再使用时一定要记得释放,调用函数free
    使用示例:
      char *pTemp = NULL;
      pTemp = (char *)malloc(10 * sizeof(char));
    个人理解:
    [1]申请空间大小时,利用sizeof做出计算,这样保证会分配正确数量的内存空间;
    [2]malloc返回的内存是没有被初始化的,所以可能包含着任何的随机垃圾,应该在其后马上调用memset函数进行初始化为0的操作;
     
    calloc
    函数原型: void *calloc(size_t nelem, size_t elsize);
    函数描述: 分配指定长度的内存空间
    入口参数: nelem    元素的个数(如为10个char申请空间,则为10)
                   elsize     元素所占用的字节(如为char申请,则为sizeof(char))
    出口参数: 无(或为空)
    返回值:    如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
    函数说明    不再使用时一定要记得释放,调用函数free
    使用示例:
    char *str = NULL;
    str = calloc(10, sizeof(char));
    个人理解:
    [1]calloc实际上也只能算作是malloc的一种简单的封装;
    [2]它会自动的把动态分配的内存进行清0操作,并且保证了分配数量的正确,所以建议使用。
     
    其他说明:
    进程对动态内存的分配请求被认为是不紧迫的。例如,当进程的可执行文件被装入时,进程并不一定立即对所有的代码进行访问。
    类似地,当进程调用malloc() 请求动态内存时,并不意味着进程很快就会访问所有获得的内存。
    因此一般来说,内核总是尽量推迟给用户态进程动态分配内存。

    这里只是简单的做个说明……

    ------------------------------------------------------------------------------------------------------------

    自定义类型
    简单的用一个新的类型名代替原有的类型名


    typedef int Integer;
    int i,j;
    Integer k;


    //声明结构体
    typedef struct{


       int month;
       int day;
       int year;
    }Date;                   //用typedef 生命的结构体,原结构体变量变成了一个新的类型了


    Date birthday;    
    Date *p;


    //定义数组
    typedef int Num[100];
    Num a;


    //定义指针
    typedef char *String
    String p,s[10];


    //定义返回值为int类型无参数的函数指针
    typedef int (*pointer)();
    pointer p1,p2;


    ###
    typedef 只是对已经存在的类型制定一个新的类型名,而没有创造新的类型
    用typedef声明数组类型 指针类型 结构体类型 共用体类型 枚举类型等
    typedef 与 #define 表面上有相似之处
    当不同的源文件中用到同一类型的数据时,常用typedef声明一些数据类型,可以吧所有的typedef名称声明单独放在一个头文件中
    使用typedef名称有利于程序的通用与移植,有时程序会依赖与硬件的特性,用typedef类型便于移植。


    ------------------------------------------------------------------------


    使用位域定义与结构体相仿
    格式:
    struct 位域结构名{
      
           类型说明   位域名:位域长度;


    }


    位域长度不能超过该类型的位数
    可以将该类型所占的其他位忽略
    可以无位域名,表示填充或者调整位置


    例如:
    struct sta{


        unsigned int  a:4; //占用半个字节 4位
        unsigned int :0;    //空域 第一个字节的剩余位全清零
        unsigned int b:4;   //占用半个字节 4位
        unsigned int c:4;   //占用半个字节 4位


    }
    >>>>>


    |   a       |    空   |
    |   b       |     c   |

    再例如:
    struct stb{


      int a:1;    //占用1位
      int  :2;     //表示 2个位 不用
      int b:3;    //占用3位
      int c:2;    //占用2位


    }


    |   a 1   |   空 2   |   b 3  |   c  2 |      //共占8个位


    ------------------------------------------------------------------


    动态内存管理
    非静态的局部变量是分配在内存中的动态存储区,这个存储区是一个称为 栈  的区域


    如:int a 存放在栈区


    C语言 还允许建立动态分配区域,以存放一些临时用的数据,这些数据需要随时开辟,不需要的时候试试释放,这些数据是临时存放在一个特别
    的自由存储区,成为 堆 区


    如:全局变量 内存管理的手动分配单元  静态变量都是存在 堆区


    关于静态和动态
    静态内存分配是在程序执行之前进行的,因而效率比较高,但是它缺少灵活性,要求在程序执行之前,就知道所需要的内存的类型和数量
    静态对象是有名字的变量,我们直接对起进行操作,而动态的对象是没有名字的变量,我们通过指针间接的对他进行操作
    静态对象由编译器自动释放处理,动态变量需要手工释放


    方法:


    malloc 
    calloc
    free
    realloc


    1、malloc(大小)   分配到堆区
    void * malloc(usingned int size);单位是(byte)字节数 
              其作用是在内容的动态存储区分配一个长度位 side 空间,此函数是一个指针型函数,返回的指针是该分配区域的开头的位置(或首地址)
     注意指针的类型位void 即不指向任何类型的数据,只提供一个地址。放什么类型的数据,强制转换位什么类型。
     如果函数未能成功申请到空间(内存不足),返回空指针 NULL


    如:
    //分配40个字节的连续空间,让a指向新空间的首地址
    int *a =(int*)malloc(40);
    //判读是否申请成功
    if(a == NULL){


    }


    ========================
    练习:申请两个Student类型的空间


    struct  Student stu;
    *p = (struct *Student) malloc(sizeof(struct Strdent)*2);
    //判断
    if(p==NULL){


    }


    另一种:使用typedef
    typedef struct Student{


      …..
    ……
    }stu;


    stu *p = (stu*) malloc( sizeof(stu)*2 );
    //判断
    if(p==NULL){


    }
    =========================


    2、 calloc(数量,大小)  分配到堆区


    viid * calloc(unsigned n,unsigned size);   上例改为 int a = sizeof(stu);   stu *b = (stu*) calloc(2,a);
    其作用是在内存的动态存储区中分配n个长度位 size的连续空间,这个空间一般比较大,足以保存一个数组
    可以为一维数组开辟动态存储空间,n为数组元素个数,每个元素长度位size,这就是动态数组。


    calloc  ----->malloc
    如:calloc(m,n)   ---->malloc(m*n);


    malloc  ----->calloc
    如:malloc(a)  ---->calloc(1,a);


    例如:int *a = (int*)calloc(10,sizeof(int));  if(a==NULL)  40个字节,等于分配长度为 10 的一维数组


    3、free(指针变量) 
    void free(void *p);   p=NULL;
    其作用是释放指针变量p所指向的动态空间,这部分空间能重新被其他变量使用,p应是最近一次调用calloc或malloc函数时得到的函数返回值
    free(p)释放指针变量p所指向的已分配的动态空间,但是注意,当p被释放后,p变为野指针,所以一定要加一句  p=NULL或p=0;
    free函数无返回值
    动态分配的空间用完后,必须要释放。


    ***** 注意 *****
    在使用malloc或者cmalloc申请空间时,如 int *p  = (int*)malloc(40); 
    p指针不允许进行 ++p  或者 --p,这样将导致 部分内存区域无法归还,导致内存泄露。


    4、realloc(指针,大小)
    void *realloc(void *p,unsigned int size);
    如果已经通过malloc函数获取到了动态的空间,想改变大小,可以使用relloc函数重新分配
    用realloc 函数讲p所指向动态空间的大小改为size,p的值不变,如果重新分配不成功,返回NULL(  "p=(int*)relloc(p,20)"  这句话有问题,一旦重新分配不成功,p=NULL,将会导致p指向的原来的空间也无法找到,无法归还,将导致内存泄露);

    void *realloc(void *p, size_t size);
    将p所指向的对象的大小改为size个字节.
    如果新分配的内存比原内存大, 那么原内存的内容保持不变, 增加的空间不进行初始化.
    如果新分配的内存比原内存小, 那么新内存保持原内存的内容, 增加的空间不进行初始化.
    返回指向新分配空间的指针; 若内存不够,则返回NULL, 原p指向的内存区不变.

    p= (char *) realloc(p, 256);
    返回指向新分配空间的指针; 若内存不够,则返回NULL, 原p指向的内存区不变.
    要是对内存空间不够,原p指向的空间因为p=NULL后而丢失,
    危险的内存泄露

    防止内存泄露:

    char *p,*q;
    p = (char *) malloc(sizeof(char));
    q= (char *) realloc(p, 256);
    if (q==NULL)
    return -1;
    p=q;

    char *= (char *) malloc(sizeof(char));
    p
    = (char *) realloc(p, 256);
  • 相关阅读:
    java 验证码
    时间日期转换+两个日期相减
    java创建文件和目录
    java获取文件名的三种方法
    获取当前日期前100天的日期
    字符串去重
    Java,数据库中的数据导入到Excel
    两个list<object> 比较 得到相同数据 差异数据
    Springmvc中@RequestParam传值中文乱码解决方案
    将src非空的属性注入到des中
  • 原文地址:https://www.cnblogs.com/kungfupanda/p/2824606.html
Copyright © 2011-2022 走看看