zoukankan      html  css  js  c++  java
  • C语言的内存管理

    堆和栈的区别:

    栈的特征

    执行的速度相对较快;

    空间较小;

    生存期由系统决定;

    作用域较小;

    有名空间,可以通过变量名或者数据名访问;

    堆的特征

    执行的速度相对较慢;

    空间较大;

    生存期由“自己”决定,malloc申请,free释放;

    作用域很大(整个程序都可以访问);

    无名空间,只能通过指针使用;

    C语言空间的申请

    malloc

    功能:

    分配 size 字节的未初始化内存。若分配成功,则返回指向分配内存块最低位(首位)字节的,为任何拥有基础对齐的对象类型对齐的指针。

    头文件:

    #include<stdlib.h>
    原型:
    void* malloc( size_t size );

    参数:

    size - 要分配的字节数

    返回值:

    成功时:返回指向新分配内存的指针。为避免内存泄漏,必须用 free() 或 realloc() 解分配返回的指针。

    失败时:返回空指针。

    说明:

    malloc申请的空间为连续空间;malloc申请的是没有初始化的空间;

    返回值类型是void * 该类型表明malloc返回的地址空间中的数据类型是不确定,必须经过强制类型转换才可以使用。

    realloc

    功能:

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

    头文件:

    #include <stdlib.h>
    原型:
    extern void *realloc(void *mem_address, unsigned int newsize);

    参数:

    mem_address - 当前的指针

    newsize - 重新分配空间的大小

    返回值:

    如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

    说明:

    如果mem_address为NULL,则realloc()和malloc()类似。分配一个newsize的内存块,返回一个指向该内存块的指针。

    如果newsize大小为0,那么释放mem_address指向的内存,并返回NULL。

    如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或者分配新的内存块),则返回NULL。而原来的内存块保持不变。

    假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址

    如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。

    传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的

    传递给realloc的指针可以为空,等同于malloc。

    实例:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int main()
    {
       char *str;
     
       /* 最初的内存分配 */
       str = (char *) malloc(15);
       strcpy(str, "runoob");
       printf("String = %s,  Address = %p
    ", str, str);
     
       /* 重新分配内存 */
       str = (char *) realloc(str, 25);
       strcat(str, ".com");
       printf("String = %s,  Address = %p
    ", str, str);
     
       free(str);
       
       return(0);
    }

    calloc

    功能:

    在内存的动态存储区中分配num个长度为size的连续空间;

    头文件:

    #include <stdlib.h>
    原型:
    void* calloc(unsigned int num,unsigned int size);

    参数:

    num - 对象个数

    size - 对象占据的内存字节数,相较于malloc函数,calloc函数会自动将内存初始化为0

    返回值:

    成功时,返回指向新分配内存的指针。为避免内存泄漏,必须用 free() 或 realloc() 解分配返回的指针。

    失败时,返回空指针。

    说明:

    因为对齐需求的缘故,分配的字节数不必等于 num*size 。

    初始化所有位为零不保证浮点数或指针被各种初始化为 0.0 或空指针(尽管这在所有常见平台上为真)。

    因为calloc()函数会清空分配的内存,而malloc()函数不会,所以可以调用以“1”作为第一个实参的calloc()函数,为任何类型的数据项分配空间。

    实例:

    #include<stdio.h>
    #include<stdlib.h>
    int main()
    {
        int i;
        int* pn = (int*)calloc(10, sizeof(int));
        for(i = 0;i < 10;i++)
            printf("%d", pn[i]);
        printf("
    ");
        free(pn);
        return 0;
    }

    alloca

    功能:
    alloc是在栈(stack)上申请空间,该变量离开其作用域之后被自动释放,无需手动调用释放函数。
    头文件:
    #include<stdlib.h>
    原型
    void * __cdecl  alloca(size_t);

    参数:

    size - 要分配的字节数

    返回值:

    函数返回一个指向申请到的空间的void型指针.

    说明:

    在某些系统中会宏定义成_alloca使用.

    不提倡使用此函数:

    在调用 alloca() 的函数返回的时候, 它分配的内存会自动释放。也就是说, 用 alloca 分配的内存在某种程度上局部于函数的“堆栈帧”或上下文中。

    alloca() 不具可移植性, 而且在没有传统堆栈的机器上很难实现。 当它的返回值直接传入另一个函数时会带来问题, 如 fgets(alloca(100), 100, stdin)。

    由于这些原因, alloca() 不合标准, 不宜使用在必须广泛移植的程序中, 不管它可能多么有用。 既然 C99 支持变长数组(VLA), 它可以用来更好的 完成 alloca() 以前的任务。

    C语言空间的释放

    free

    原型:

    void free(void *ptr);

    功能:

    释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。

    头文件:

    #include <stdlib.h>

    参数:

    ptr - 要释放的空间的指针

    返回值

    该函数不返回任何值。

    说明:

    不能传NULL;

    不能释放已经被释放的空间;

    不能使用已经被释放的空间;

    当程序运行过程中申请了空间,但是没有free的话,会造成内存泄漏.一部分的内存没有被使用,但是由于没有free,因此系统认为这部分内存还在使用,造成不断的向系统申请内存,使得系统可用内存不断减少.但是内存泄漏仅仅指程序在运行时,程序退出时,OS将回收所有的资源.因此,适当的重起一下程序,有时候还是有点作用.

    malloc函数详细说明

    在C语言中只能通过malloc()和其派生的函数进行动态的申请内存,而实现的根本是通过系统调用实现的(在linux下是通过sbrk()系统调用实现)。

    malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

    malloc()在运行期动态分配分配内存,free()释放由其分配的内存。malloc()在分配用户传入的大小的时候,还分配的一个相关的用于管理的额外内存,不过,用户是看不到的。所以,实际的大小 = 管理空间 + 用户空间,malloc(0)的有效内存大小为24,32位中为12,准确的说是至少是这么多,并且这些内存是可以用的。

    #include<stdio.h>
    #include<stdlib.h>
    
    int main()
    {
        char *p=(char *)malloc(0);
        char *p1=(char *)malloc(5);
        char *p2=(char *)malloc(25);
        char *p3 = (char *)malloc(39);
        char *p4 = (char *)malloc(41);
    
        printf("p size:%d
    ",malloc_usable_size(p));
        printf("p1 size:%d
    ", malloc_usable_size(p1));
        printf("p2 size:%d
    ", malloc_usable_size(p2));
        printf("p3 size:%d
    ", malloc_usable_size(p3));
        printf("p4 size:%d
    ", malloc_usable_size(p4));
    
        free(p);
        free(p1);
        free(p2);
        free(p3);
        free(p4);
        return 0;
    }

    8a617568-3b2d-4c10-8c62-91b6e9a7d0b9

    此外,堆中的内存块总是成块分配的,并不是申请多少字节,就拿出多少个字节的内存来提供使用。堆中内存块的大小通常与内存对齐有关(8Byte(for 32bit system)或16Byte(for 64bit system)。

    因此,在64位系统下,当(申请内存大小+sizeof(struct mem_control_block) )% 16 == 0的时候,刚好可以完成一次满额的分配,但是当其!=0的时候,就会多分配内存块。

  • 相关阅读:
    #莫比乌斯函数,Miller-Rabin#洛谷 3653 小清新数学题
    #Dijkstra,二进制拆位#洛谷 5304 [GXOI/GZOI2019]旅行者
    #dp#洛谷 4158 [SCOI2009]粉刷匠
    #李超线段树,树链剖分#洛谷 4069 [SDOI2016]游戏
    #线段树合并#洛谷 3224 [HNOI2012]永无乡
    #主席树,dsu on tree,树上倍增#洛谷 3302 [SDOI2013]森林
    #树状数组,CDQ分治#洛谷 4390 [BOI2007]Mokia 摩基亚
    #单调队列#JZOJ 1753 锻炼身体
    #约数#洛谷 4296 [AHOI2007]密码箱
    #队列#洛谷 6033 合并果子 加强版
  • 原文地址:https://www.cnblogs.com/WindSun/p/11286282.html
Copyright © 2011-2022 走看看