动态内存管理

本文介绍了动态内存管理的基本概念,包括malloc、calloc、realloc和free等函数的用法,阐述了动态内存管理的必要性,并列举了如内存访问越界、空指针解引用等常见错误及其危害。同时,强调了动态内存管理中的注意事项,如内存泄漏和多次释放等问题,帮助读者理解和避免这些错误。

写作不易,点个赞吧铁铁,文中若有不妥之处,恳请各位读者批评指正



一、什么是动态内存管理?

       一种内存管理方法。对内存空间的分配、回收等操作在进程执行过程中进行,以便更好地适应系统的动态需求,提高内存利用率


二、为什么需要动态内存管理?

     对于初学者而言,已经基本可以掌握的内存开辟方法:定义+初始化的方法。
   int a=0; int arr[]={0,1,2,3}
  char arr[]={"abcd"}等等

  但是上述内存的开辟大小是在编译前就确定的,同时数组在声明的时候又必须指定数组长度,    它所需要的内存在编译的时候分配;【这种开辟方式的特点

  但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道, 那数组的编译时开辟空间的方式就不能满足了,而且盲目的开辟内存只会造成内存的浪费
              【这时候就只能试试动态存开辟了】

三、动态内存函数

 1、malloc

定义  : void* malloc (size_t size);  (stdlib.h)

  作用 

      向内存申请一段连续的、可用的空间

  特点

 //返回类型为void*,参数为开辟空间的大小(单位字节)

  1. 这个函数向内存申请一段连续可用的空间,并返回指向这个空间的指针
  2. 如果开辟成功,则返回一个指向开辟好空间的指针。
  3. 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查(assert)
  4. 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己 强制类型转换
  5. 如果参数 size 0malloc的行为是标准是未定义的,取决于编译器。

  实例

运行结果为0 1 2 3 4


#include<stdio.h>
#include<stdlib.h>
int main()
{
    int* p = (int*)malloc(5 * sizeof(int));
    for (int i = 0;i < 5;i++)
    {
        *(p + i) = i;
        printf("%d ", *(p + i));
    }
    free(p);
    p = NULL;
    return 0;
}

  2、free 

定义void free(void*str);(stdlib.h)

  作用

  free是c语言提供的,专门用来释放、回收动态开辟出来的空间的函数。

  特点

  1. 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的,运行代码的时候将会报错
  2. 如果参数 ptr NULL指针,则使用free函数将什么事都不不会发生。

    (举例同上malloc实例)

 3、calloc

定义 void*calloc(size_t num,size_t size)

    (stdlib.h)

  作用 

它的作用同malloc相似,也是向内存申请一段连续的、可用的空间。

  特点

  1. 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0
  2. 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

  举例

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int* p = (int*)malloc(5 * sizeof(int));
    printf("p(malloc):");
    for (int i = 0;i < 5;i++)
    {
        printf("%d ", *(p + i));
    }printf("\n\n");
    int* c = (int*)calloc(5, sizeof(int));
    printf("c(calloc):");

    for (int i = 0;i < 5;i++)
    {
        printf("%d ", *(c + i));
    }
    printf("\n\n");
    free(p);free(c);
    p = NULL;c=NULL;
    return 0;
}

4、realloc

void*reallocvoid*,size_t size) stdlib,h

  作用

  重新调整已开辟空间的大小。
realloc函数的出现让动态内存管理更加灵活。在使用malloc或者calloc函数的时候,可能会遇到动态开辟的内存仍然不够的情况,会觉得申请的空间过大或者过小,那为了合理地使用内存,避免再去重新开辟一段内存空间,造成难以维护的情况,那么将会使用到realloc函数。 realloc 函数就可以做到对动态开辟内存大小的调整

  特点

  1. 指针p是要调整的已经开辟的空间的地址
  2. size是调整后的大小(单位:字节)
  3. 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到的空间。
  4. 在使用realloc调整动态内存的时候存在两种不同的开辟方法:

   方法1、原有空间之后存在足够的且连续的空间:
   方法2、在堆空间中另找一块连续的空间;

   

 情况 1
当是情况 1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
 情况 2
当是情况 2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小
的连续空间来使用。这样函数返回的是一个新的内存地址。

  实例

  int*p=(int*)malloc(5*sizeof(int));
//若空间不够了,使用realloc
   int*p=(int*)realloc(p,10*sizeof(int));

四、常见动态内存错误

 1、动态内存访问越界

类似于数组int arr[10]访问越界:访问了不属于它的空间。

int arr[10];   arr[11]=0;

 动态内存开辟的空间同样存在越界访问的问题

案例
 

int i = 0;
    int* p = (int*)malloc(10 * sizeof(int));
    if (NULL == p)
    {
        exit(EXIT_FAILURE);
    }
    for (i = 0; i <= 10; i++)
    {
        *(p + i) = i;//当i是10的时候越界访问
    }
    free(p);
    p = NULL;

 2、对NULL空指针进行解引用操作 

int * p = ( int * malloc ( INT_MAX / 4 );
* p = 20 ; //如果malloc开辟空间失败,则会返回空指针(NULL),此时将空指针赋给p
//解引用后就是对空指针的解引用

这种操作会引起程序或者系统崩溃

 3、对非动态开辟内存使用free释放

int a=10;   int*p=&a;  free(p);

此操作会引起程序崩溃; 

 4、free未释放动态开辟的内存

       1、未使用free函数

这种错误较为隐蔽,错误产生了但是不容易被发现

int *p=(int*)malloc (5*sizeof(int));//未使用free

未使用free不会报错,但是存在内存泄漏,影响程序的正常运行。


       2、使用了free函数,但只释放了部分内存


    int* p = (int*)malloc(5 * sizeof(int));
    p++;  //此处将p的地址向后挪了一位;
    free(p);
p=NULL;

 

  • 当p的所指向的位置向后移位的时候,free只释放了部分动态开辟内存,仍存在一部分内存没有被回收,也是内存泄漏的一种。 此时运行程序就会发生崩溃。

 5、对一块动态开辟内存进行多次释放

int *p=(int*)malloc (5*sizeof(int));  //假设开辟成功

free(p);

free(p);

 同样会报错。
解释:当你将p  free释放的时候,p指向的这块空间已经不属于malloc等函数动态开辟的空间,系统可能将这块空间分配给了其他程序,这时在此使用free就相当于释放了非动态开辟内存,就会同上面一样报错。

总结

此文章讲解了什么是动态内存管理,以及一些常用的动态内存管理的函数,和常见错误

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值