动态内存管理

1.1 为什么要有动态内存分配呢?

我们已经掌握的内存开辟有两种方式:

int val=10;

char ch[5]; 

对于方式1,我们开辟的是一个整形大小(4个字节)的大小。对于方式2,我们开辟了一个连续的空间(5个字节)。在这里我们开辟的空间是固定的,我们无法在后续改变内存空间的大小,显得特别的不方便,所以我们要引入动态内存开辟来使得内存分配更为灵活。

2.1 malloc和free

2.1.1 malloc函数

void* malloc size_t size )

1.对于malloc函数,使用malloc函数向内存申请一块连续可用的空间,内存大小的单位是字节。 2.对于malloc函数,函数参数是字节,返回值是void*,在这里void*可以是int*,double*等,其他指针类型,这里由使用者自己来决定。                                                                                                                                                3.当malloc函数返回一个空指针NULL的时候代表这个函数调用失败,所以我们一定要对malloc函数的返回值进行检查。                                                                                                                                   4.当我们参入的参数是0的时候,malloc开辟的空间是取决于编译器的。

2.1.2 free函数

void free(void* ptr

1. 对于 free 函数,用来释放一块动态开辟的空间,对于不是动态开辟的空间不可用free来释放。       2. free 函数的参数是void* ptr,这里的参数根据使用者自己来决定。                                                     3. 我们将一块空间free掉之后我们要把指向那块空间的指针置为空指针NULL,不然就会产生野指针的情况。      

2.1.3 malloc和free的使用

malloc函数和free函数都包含于头文件<stdlib.h>中。我们通过下面的例子来看看如何使用malloc和free。

#include<stdio.h>
#include<stdlib.h>

int main(){
   int *p=malloc(20);
   for(int a=0;a<5;a++){
      *(p+a)=a+1;
       printf("%d ",*(p+a)); 
   }
   free(p);
   p=NULL;
   return 0;
}

我们在使用free的时候不可以只释放这个空间的一部分,这样操作是不被允许的。什么意思呢? 

 

我们开辟了一块空间我们从(p+1)的地址处进行释放,将 p 到 p+1 这一块空间留下来这样是不被允许的。同时我们将malloc开辟的空间进行释放之后我们的那个指针依然指向那块空间,只是对那块空间没有使用权了。

我们在 free 一块空间的时候也容易犯另外一个错误:我们的指针不指向开始时的起始地址。

#include<stdio.h>
#include<stdlib.h>

int main(){
   int *p=malloc(sizeof(int)*5)
   int a=0;
   for(a=0;a<5;a++){
      *p=a+1;
       P++;//程序走出for循环之后p指向的不是初始位置
   }
   free(p);
   p=NULL;
   return 0;
}

 3.1 calloc和realloc

3.1.1 calloc函数

calloc函数和ralloc函数十分的像,也是开辟一块连续可用的空间,但是calloc会讲地址的内容初始化为0。

void* calloc(size_t num, size_t size)

1.calloc函数是用来开辟一个个数为num个,大小为size的连续可用的空间。                                           2.函数的参数1是空间的个数,参数2是每个num的大小。                                                                              3.函数的返回值是void *,根据用户自己的使用情况来定义。

我们通过一段代码来看一下calloc函数的使用情况:

#include<stdio.h>
#include<stdlib.h>

int main(){
   int *p=calloc(5,sizeof(int));
   int a=0;
   for(a=0;a<5;a++){
      printf("%d "*(p+a)); 
   }
   free(p);
   p=NULL:
   return 0;
}

这里输出的结果是:0 0 0 0 0  

所以我们在申请一块空间并且要对其 进行初始化的时候用,calloc函数函是很方便的。 

3.1.2 realloc函数

我们在动态开辟的时候,有时候要根据实际的情况对这段空间进行扩容,这个时候我们就要用到realloc函数。

void* realloc( void* ptr ,size_t size)     

 我们在调用realloc函数的时候会出现两种情况:

一. 在原有的空间后面有足够的空闲空间来接收我们要新开辟的空间。

二. 在原有的空间后面没有足够的空闲空间来接收我们新开辟的空间。

情况1: 我们会在原有的地址后面开辟新的空间,函数的返回值仍然是原始的地址。

情况2: 我们无法在原有的地址后面开辟新的空间,函数会在堆区寻找一块新的空间,这块空间可以接收原有的空间和新开辟的空间,返回新空间的初始地址。

当realloc函数在调用失败后就会返回一个空指针,所以我们在使用时要注意判断返回值是不是空指针。

#include<stdio.h>
#include<stdlib.h>

int main(){
   int *ptr=(int *)malloc(100);
   if(ptr!=NULL){
      //业务处理
   }else {return 1;}

   //代码1:直接realloc后的返回值存在ptr中
   ptr=(int *)realloc(ptr,1000);
   
   //代码2:将realloc的返回值先存在一个指针p中,p不为NULL再p赋值给ptr
   int *p=(int *)realloc(ptr,1000);
   if(p!=NULL){
       ptr=p;
   } else {return 1;}
   return 0;
}

 4.1 动态内存的常见错误

4.1.1 对NULL的解引用操作

#include<stdio.h>

int main(){
   int *p=(int *)malloc(INT_MAX/4);
   *p=20;//当malloc函数开辟空间失败后九返回NULL。
   return 0;
}

4.1.2 free动态开辟内存的一部分

#include<stdio.h>

int main(){
   int *p=(int *)malloc(5*sizeof(int));
   p++;
   free(p);
   return 0;
}

4.1.3 free的非法使用

#include<stdio.h>

int main(){
   int *p=20;
   free(p); 
   return 0;
}

4.1.4 对动态开辟的空间的越界访问

#include<stdio.h>

int main(){
   int *P=(int *)malloc(5*sizeof(int));
   int a=0;
   for(a=0;a<=5;a++){
      *(p+a)=a+1;
        printf("%d ",*(p+a));
   }
   
   return 0;
}

4.1.5 在动态内存开辟之后没有进行free,导致内存泄漏

#include<stdio.h>
  
void test{
  double *p=(double *)malloc(5*sizeof(double));
}

int main(){
   test();
   return 0;
}

4.1.6 对一块空间进行多次的free

#include<stdio.h>

int main(){
   int *p=(int *)malloc(5*sizeof(int));
   free(p);
   free(p);
   return 0;
}

以上就是我们在编程中容易出现的错误,需要我们注意。 

 

 

 

 

 

ui

  • 54
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Main. 24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值