zoukankan      html  css  js  c++  java
  • malloc realloc calloc free

      自上次发现自己对这几个C函数不熟悉,就打算抽空整理一下,也就现在吧。这几个函数都是跟堆内存打交道的,还有一个好玩的函数--alloca,它是跟栈内存打交道的,我想留在以后研究出好玩点的来,再专门为其写一篇铭文。

    1.malloc:

    头文件:<stdlib.h>

    原型:extern void *malloc(unsigned int num_bytes);

    功能:分配长度为num_bytes字节的内存块。如果分配成功则返回指向被分配内存的指针,否则返回NULL。

    机理:malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针,因此在调用malloc动态申请内存块时,一定要进行返回值的判断。

    2.realloc:

    头文件:<stdlib.h>

    原型:extern void *realloc(void *mem_address, unsigned int newsize);

    功能:改变指针mem_address所指向区域的大小为newsize。如果成功则返回指针mem_address,否则返回NULL。

    机理:先判断当前的指针mem_address是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

    3.calloc:

    头文件:<stdlib.h>

    原型:void* calloc(size_t n, size_t size); 

    功能: 在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。

    机理:在malloc的基础上加上内存空间清0操作。

    4.free:

    头文件:<stdlib.h>

    原型:void free (void* ptr);

    功能:释放指针ptr指向的堆内存。

    5.Example

    #include <stdlib.h>     /* malloc, calloc, realloc, free */
    
    int main ()
    {
      int * buffer1, * buffer2, * buffer3;
      buffer1 = (int*) malloc (100*sizeof(int));
      buffer2 = (int*) calloc (100,sizeof(int));
      buffer3 = (int*) realloc (buffer2,500*sizeof(int));
      free (buffer1);
      free (buffer3);
      return 0;
    }

    下面是好玩的地方:

    1.malloc与calloc的区别:函数malloc不能初始化所分配的内存空间,而函数calloc能。函数calloc() 会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为0;如果你是为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针;如果你为实型数据分配内存,则这些元素会被初始化为浮点型的零.

    2.realloc需要注意的安全问题:

    (1)从realloc的机理得知,其返回的地址不一定是原地址,这点尤为重要. realloc可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变.当然,对于缩小,则被缩小的那一部分的内容会丢失.realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址.相反,realloc返回的指针很可能指向一个新的地址.

    (2)下面说下realloc的扩展:

    1】. 与名字相符,真正的realloc,参数ptr和size均不为NULL,重新调整内存大小,并将新的内存指针返回,并保证最小的size的内容不变;
    2】. 参数ptr为NULL,但size不为0,那么行为就等于malloc(size);
    3】. 参数size为0,则realloc的行为为free(ptr);这时原有的指针已经被free掉,不能继续使用。而此时realloc的返回值为NULL。这意味着不检查realloc的返回值,直接使用,会导致crash。
    下面说两种bug:
    <1>
    void *ptr = realloc(ptr, new_size);
    if (!ptr) {
        错误处理
    }

    这里就引出了一个内存泄露的问题,当realloc分配失败的时候,会返回NULL。但是参数中的ptr的内存是没有被释放的。如果直接将realloc的返回值赋给ptr。那么当申请内存失败时,就会造成ptr原来指向的内存丢失,造成泄露。

    正确的处理应该是这样:

    void *new_ptr = realloc(ptr, new_size);
    if (!new_ptr) {
        错误处理。
    }
    ptr = new_ptr

    <2>

    void *new_ptr = realloc(old_ptr, new_size);
     //其它代码
     ...... ......

    这种bug由一种不好的编程习惯引发的。即认为申请内存始终可以成功,因此并不检查malloc的返回值。这在一般情况下,不会引发问题。但是对于realloc来说,当new_size为0时,realloc返回NULL。而在后面的代码上,继续使用new_ptr,比如会导致程序crash。

  • 相关阅读:
    excel生成数据地图
    利用web of science做论文综述
    机器学习算法一览图
    什么是机器学习?
    机器学习十大算法(二)
    机器学习十大算法(一)
    django传值出现二进制乱码(基于python3)
    解决mysql的动态添加字段以及数据的方法(基于python3.6)
    odoo权限控制
    win32service的解决办法(pywin32)
  • 原文地址:https://www.cnblogs.com/jiu0821/p/4587505.html
Copyright © 2011-2022 走看看