【C语言】动态内存管理

【C语言】动态内存管理

C语言 提供了一些用途较为特殊的函数,不像变量命名那样在定义之初将变量的空间固定,可以依照自己的需求,比较灵活的开辟空间,保证空间的利用效率;

首先介绍内存的简单概念:

\\内存主要分为三大区域,用于存放不同类型的变量:
    栈区:存放临时的变量,例如局部变量,形参,也就是我们常用的开辟空间方法;
    静态区:存放静态变量 (static 定义),全局变量;
    堆区:使用动态内存开辟的主要区域;

C语言中参与动态内存分配的函数主要有: malloc calloc realloc free

malloc

void *malloc( size_t size );
//malloc 函数的含义是:在 堆区 申请了 size 个 字节 的空间,最后以 void* 的类型返回已申请空间的首地址;
//不会对申请的空间进行初始化;

一般在赋值过程将malloc开辟的空间转换成自己所需的指针类型,以便于维护。例如:

#include <stdlib.h>
int* p = (int*)malloc(50);//向内存申请50个字节,用int*类型维护;

if( NULL == p)
    return;     /* 判断有效性 */
*p = 0; /* 如果不对p的有效性进行检查,这样可能会造成对NULL的解引用,*/

如果开辟失败,则会返回空指针 NULL

free

该函数主要是对向堆区申请的空间进行释放(将空间交还操作系统),其格式为:

void free( void *memblock );
// memblock是存放动态内存开辟的首地址的指针变量,函数无返回值

memblock存放的如果不是动态内存开辟的首地址(常规定义),free行为是未知的;

如果memblock存放的是NULL,free函数没有任何行为;

int* p = (int*)malloc(50);
free(p);                    //在使用free函数后,p指向的空间已被归还,但仍然指向首地址,
p = NULL;                   //所以在释放后一定要手动置空;

calloc

void *calloc( size_t num, size_t size );
//calloc 函数会在 堆区 上申请一块连续的 num 个大小为 size 的空间,并将此空间上的值置为0(malloc不初始化)
//返回申请空间的首地址;申请失败返回null;

其他使用方法与 malloc 相同

int* p = (int*) calloc(10, sizeof(int));
free(p);
p = NULL;   /* 手动置空 */
if( NULL == p)
    printf("%s\n",strerror(errno))   /* 报告错误原因 */

realloc

该增容函数在动态内存开辟中最为灵活,是动态内存开辟函数的**“主力”**

在使用动态内存的过程中,可以用该函数改变所申请内存空间的大小,提高内存利用;

void *realloc( void *memblock, size_t size );
/* 重新开辟内存块;*/
memblock 变量存放的是指向之前开辟好的空间的首地址;
realloc函数会将memblock指向空间的内容拷贝至新开辟的 大小为 size 个字节的空间中,并将此空间的首地址以 void* 类型的方式返回;
/*  realloc会将之前memblock指向的空间free掉,但不会将memblock改为空指针,需手动置空 */

realloc 有两种开辟方法:

 1. 当memblock 指向开辟的空间后面有足够的未被使用的空间时,realloc会在此空间之后开辟空间,返回的地址与memblock存放的地址相等;
    2. 当memblock 指向开辟的空间后面没有有足够的未被使用的空间时,realloc会重新找一块空间,将memblock的数据拷贝过去,free掉memblock指向的空间,并将新的空间地址返回;
p = (int*)realloc(p, 30);
/* realloc使用失败后,返回一个空指针NULL,而不是一开辟好的memblock指向的空间,可能会导致memblock存放的首地址的丢失,因此在 使用realloc,一定要保证有变量存放已开辟空间的首地址;*/
/* 没有释放掉动态开辟的内存块,会导致内存泄漏 */
int* ptr = (int*)realloc(p, 40);
if( ptr != NULL)
   p = ptr;              /* 防止增容失败,导致源空间地址丢失 */

注意问题

  1. 动态空间的越界访问:如果需要增容空间,使用realloc,否则非法使用未开辟空间会造成未知错误;

  2. 非动态开辟的空间用free释放:常规定义的变量用free释放,程序会报错;

  3. 不能对存放已动态开辟的变量进行自加或自减操作,否则会导致使用free释放不完全,导致内存泄漏;

  4. 严禁对同一块空间进行过次free释放

  5. 动态内存开辟忘记释放(即内存泄漏):> 空间回收有两种方式:1. free释放 2. 程序结束退出,OS自动回收

    内存泄漏:在写有关动态内存开辟函数时,忘记使用完释放,导致程序运行过程中,即使该空间未被该程序使用,其他程序也无法使用这片空间,造成空间浪费;如果特定程序一直在开辟空间而不回收,会导致内存慢慢好干,没有空间可用,导致程序崩溃。

    void GetMemory(char* p)
    {
        p = (char*)malloc(100);            
        /* p中存放开辟空间的首地址,但出函数后,p被销毁, 地址无法找到,存在内存泄漏 */
    }
    void Test(void)
    {
        char* str = NULL;
        GetMemory(str);                /* 这里采用的是值传递,将NULL指针复制到p中 */
        strcpy(str, "hello world");
        printf(str)
    }
    

    局部性原理:在使用某些数据的时候,接下来使用的数据大概率会是周围的数据,在使用内存的数据时,也会将周围数据连同使用的数据加载到缓存中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值