动态内存管理

 目录

 

一.为什么要用动态内存分配

二.malloc和free

二.1.malloc

二.2free

三.calloc和realloc

三.1calloc

三.2realloc

四.常见的动态内存错误

四.1对NULL指针的解引用操作

四.2对动态开辟空间越界访问

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

四.4使用free释放一块动态开辟内存的一部分

四.5对同一块动态内存多次释放

四.6动态开辟内存忘记释放

总结

一.为什么要用动态内存分配

二.malloc和free

二.1.malloc
二.2free

三.calloc和realloc

三.1calloc
三.2realloc

四.常见的动态内存错误

四.1对NULL指针的解引用操作
四.2对动态开辟空间越界访问
四.3对非动态开辟内存使用free释放
四.4使用free释放一块动态开辟内存的一部分
四.5对同一块动态内存多次释放
四.6动态开辟内存忘记释放


一.为什么要用动态内存分配

在我们需要存放数据的时候,我们往往是通过创建变量来向内存申请空间,比如:

int a;
char ch;
int arr[10];

局部变量在内存栈区申请一块空间,但程序运行起来申请的空间不能灵活改变,比如有些时候我们需要的空间是只有程序运行起来的时候才能确定,而创建变量来申请空间的方式显然不能满足我们的需求,于是C语言就规定了一些函数,能让程序员自己自由像内存申请空间的函数,下面让我们一一介绍。


二.malloc和free

二.1.malloc

malloc函数是向内存申请一定空间的函数,函数会返回这块空间的起始地址,看看C标准中hi如何定义的。

void* malloc(size_t size);

函数参数为需要申请内存的字节数,开辟的空间为内存中的堆区,如果申请成功,函数会返回这块空间的起始地址,如果申请失败,函数会返回一个空指针,因此我们在使用malloc需要注意一些事项。

注意事项:

1.使用之前需判断是否开辟成功,再使用这块内存。

int *p=(int *)malloc(sizeof(int));
if (p == NULL)
{
   return 1;
}

如上,申请失败,则返回非正常结束
2.要用对应的数据类型指针去接收这个无类型的指针。


二.2free

free函数主要用于收回程序员开辟的内存空间,变量可以在程序结束时操作系统自动收回,但程序员申请的空间如果不自己收回,则会在程序结束时自动收回,但如果这是一个大工程,这块空间不需要的时候,没有自己收回,那么可能会导致内存泄漏,十分危险。

void free(void *ptr);

把申请的内存地址传给函数即可释放空间,如果传的是空指针,free函数不做任何操作。

如果不是指向函数分配的内存快,则为引起未定义行为。


三.calloc和realloc
三.1calloc

calloc函数和malloc函数很相似,只是calloc函数会将申请的空间都初始化为0.

void * calloc(size_t num,size_t size);

num为要分配的元素数,size为每个元素的字节大小,并将该字节内存快初始化为0,如果申请失败,返回空指针,和malloc函数一样,申请完之后需要判断是否申请成功,并在不需要这个内存块的时候及时free收回。

三.2realloc

realloc用于改变申请的内存块大小,如果程序员需要改变原来申请的内存块大小,那么realloc可以来实现。

注意:

1.函数可能会将内存块移到新地址,在接收时可以用中间指针变量接收,否则申请失败的时候,原指针会丢失这块内存。如:

int *p=(int *)malloc(sizeof(int));
int *s=(int *)realloc(sizeof(int)*5);
{
if(s!=NULL)
  p=s;
}

2.申请新的内存空间会保留旧的内存空间的数据。

3.申请失败会返回空指针。



四.常见的动态内存错误
四.1对NULL指针的解引用操作
void test()
 {
 int *p = (int *)malloc(INT_MAX/4);
 *p = 20;//如果p的值是NULL,就会有问题
 free(p);
 }

函数可能会申请不成功,使用之前应该判断是否为空。

四.2对动态开辟空间越界访问
void test()
 {
 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);
 }

申请了多大的内存空间,就只能访问这块内存,不能越界访问其他内存空间

四.3对非动态开辟内存使用free释放
void test()
 {
 int a = 10;
 int *p = &a;
 free(p);//ok?
 }

不能对非动态开辟内存使用free释放

四.4使用free释放一块动态开辟内存的一部分
void test()
 {
 int *p = (int *)malloc(100);
 p++;
 free(p);//p不再指向动态内存的起始位置
 }

使用动态内存开辟的时候,要将内存起始地址传给free释放

四.5对同一块动态内存多次释放
void test()
 {
 int *p = (int *)malloc(100);
 free(p);
 free(p);//重复释放
 }

重复释放编译器会报错,动态内存开辟只需释放一次

四.6动态开辟内存忘记释放
void test()
 {
 int *p = (int *)malloc(100);
 if(NULL != p)
 {
 *p = 20;
 }
 }
int main()
 {
 test();
 while(1);
 }

动态内存开辟后忘记释放,会造成内存泄露,非常危险


总结

动态内存管理提高了程序员对内存使用的灵活性,同时也带来了一些风险,使用时需要十分注意。


  • 20
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值