【动态内存1】:C中内存开辟与销毁

时间:2024-03-28 07:12:54

C语言动态内存开辟与销毁:包含在头文件<stdlib.h>中

(一)malloc:开辟一块内存

(1)原型:void*malloc(size_t size);void* 类型可以强制转换为任何其它类型的指针,但反过来就不行了

(2)开辟方式:

void*malloc(size_t size);//参数为开辟数据类型*开辟数量,返回值为所申请空间的首地

void*q = (int *)malloc(sizeof(int)* 4);//开辟4个int型大小的堆内存,即16个字节

(3)malloc函数申请的空间都是从中获取的,需要手动调用free函数释放

(4)  如果开辟成功,则返回一个执行开辟好空间的指针。

      如果开辟失败,则返回一个 NULL 指针,因此 malloc 的返回值一定要做检查。

(二)calloc:也是用来动态分配,并初始化为0

 原型: void *calloc(size_t num, size_t size)

功能:为num个大小为 size 的元素开辟一块空间,并把空间的每个字节初始化为0.

(三)realloc:修改原先已分配好的内存块大小

原型:void *realloc(void *ptr,size_t size)

使用:

  • ptr是指针,指针指向需要修改的内存空间的首地址,ptr必须指向堆区空间
  • size是最终内存的大小
  • 修改ptr指向的内存空间的大小,并不会修改原来的内存空间的存储的值
  • 修改后的空间的首地址不一定和之前的相等,假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被自动free掉,realloc返回新内存的地址。
  • realloc传递的指针必须为malloc()、calloc()或者realloc()先前分配的指针

简单使用:realoc(arr,40);//arr为要扩充的内存的首地址,40为最终内存的大小

(四)内存销毁函数free

原型:void*free(void*)

使用:参数为所要释放内存的首地址,为指针类型

简单使用:

int *p = (int *)malloc(siozeof(int )* 4);

free(p);

(五)开辟与释放的具体使用:

malloc与calloc开辟与释放:

int main()
{
    int i;


    int *p = (int*)malloc(sizeof(int)*4); //开辟空间但是不做初始化
    printf("malloc申请的空间值:\n");
    for ( i=0 ; i < 4; i++)
    {
        printf("%d ", p[i]);   //printf("%d\n",*p++)也可打印出随机值,但最后释放时程序崩溃,原因是:指针++改变了地址,free时要传入的是开辟内存的首地址
    }
    printf("\n\n");

    int *q = (int*)calloc(20,sizeof(int)); //开辟空间并做0初始化
    printf("calloc申请的空间的值:\n");
    for ( i=0 ; i < 20; i++)
    {
        printf("%d ", q[i]);
    }
    printf("\n");

    free(p); //参数为所开辟内存的首地址
    p = NULL;
    free(q);
    q = NULL;

    return 0;
}

 运行结果:

【动态内存1】:C中内存开辟与销毁

malloc与realloc的开辟与释放:

int main()

{
    int *p = (int *)malloc(20*sizeof(int));
    int *pp = (int *)realloc(p, 40*sizeof(int));

    int *q = (int *)realloc(p, 0);//当size为0时,相当于free。

    printf("原来的p_Address:%x   扩容后的pp_Address:%x\n  size为0的 q_Address:%dx\n", p, pp,q);


   // free(p);
   // p = NULL; 这两行代码错误,realloc底部实现,将原来内存的值拷贝到新内存中,并且将原来的内存free掉,因此不需要再次释放p.


    free(pp);
    pp = NULL;
    return 0;
}

 运行结果:

【动态内存1】:C中内存开辟与销毁

(六)TIPS:

(1)free释放内存:将内存小块拼成大块,然后释放

(2)调用free时并没有传入内存大小,那么free函数为什么知道释放了多少字节内存???

       在函数内存块前加入了头信息,在内存块尾部加入了尾信息。

【动态内存1】:C中内存开辟与销毁

       真正的内存管理如申请/释放等,并不是由malloc或者free等库函数来负责的,而是交由操作系统去完成,它们只是维护一个空闲的链表式的内存块。例如:要申请sizeof(int)*100大小的内存空间,虽然返回的是内存大小是400,但实际上,操作系统分配时候,会多出一块用于存储内存大小的类似链表head头节点的东西,这个节点存储的是空间的首地址及分配内存的大小。当调用free函数的时候,其实它也不知道要释放内存的大小,它只需改变head头结点里的内存的大小就可以了,具体内存空间的释放由操作系统去完成。

(3)free出现崩溃的原因:

  • 越界(越界改掉尾部信息)
  1. 传参时漏掉了sizeof,例int *p = (int *)malloc(10*sizeof(int ));
  2. realloc的第二个参数写错
  • 改变了指针的指向

int *p = (int *)malloc(10*sizeof(int ));

for(int i = 0;i < 10;i++)

{

       *p = 0;

        p++;  //指针指向改变,没有指向所开辟内存的首地址

}

free(p); //出错

  • 重复释放
  • 释放不是动态申请的内存