深度剖析动态内存

为什么存在动态内存函数?

malloc

free

calloc

malloc与calloc的异同

realloc

常见动态内存使用错误

1.对NULL解引用操作

2.对动态内存开辟的空间进行非法访问

3.忘记free导致内存泄漏

4.只free掉动态内存开辟的一部分空间

5.对同一块空间多次free

6.对非动态内存空间进行free


为什么存在动态内存函数?

我们已经掌握的开辟方式有int a,char b,float arr[10]

我们会发现,它的内存大小是固定不变的,也就是随着存储的数据越来越多,迟早有一天他会超过限制,造成越界访问。

因此,我们需要一种可以随着我们需求而变化的开辟空间的方法——动态内存开辟

                                        malloc

malloc是c语言自带的一个内存开辟函数,我们先来看看它的函数类型

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

                                              free

free函数是专门用来释放掉动态内存的开辟的空间的,也是一个函数。

 我们只需要把要释放的空间的首地址传给它即可,它就会将这段动态开辟的空间释放,还给操作系统

注意:

  • 如果我们在函数内部进行动态开辟,但是没有进行释放的话,它是不会和int,char类型一样被销毁的,而是会一直存在,直到程序结束才返回给操作系统
  • free函数用来释放动态开辟的内存。
  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。
  • 任何只要是开辟的动态内存空间(堆上的),都要free释放返还给操作系统。
  • free不会把接收的指针自动置空,需要自己手动操作

                                        calloc

calloc和malloc类似,也是用来进行动态开辟内存的函数,不过其与malloc还是有一些区别所在

 malloc和calloc的异同

异:

1.函数参数和malloc不同,size是一个元素的大小,而num则是元素的个数,两个相乘才是malloc里的size。

2.calloc会将默认的元素初始化为0,而malloc则是随机值

同:

都会进行动态内存的开辟

                                            realloc

我们都将动态内存,那么这一块空间应该就是动态的。我们malloc出来的空间也是有限的,那么当他不够用的时候,就轮到realloc函数出马了,我们先来看它的声明

memblock是经过动态内存开辟后仍需拓展的空间的首地址

size是经过拓展后该空间的总大小

返回经过拓展后这一空间的首地址,类型是void*

 realloc是在堆区上继续开辟空间,但是它有两种方式,理由如下:

我们知道在堆区上存储着许多数据,动态内存开辟的空间是连续的,在堆区的位置也是相对随机的,所以在需要调整的空间后面继续追加空间的话,有可能会碰到已经存储着数据的空间,但是我们又不可能破坏这些数据,所以realloc就有两种方式进行动态内存开辟

1.在原空间后面直接追加空间

2.在堆区里另外寻找一块大小为拓展后的空间,将原来的空间拷贝过来后,将原来的空间还给操作系统,再返回这块新的大小为拓展后内存大小的空间的地址。但是如果找不到额外的空间的话,realloc就会返回NULL

其实realloc也可以和malloc一样开辟空间

int main()
{
	int* p1 = NULL;
	int* p2 = realloc(p1, sizeof(int) * 10);

	return 0;
}

                                                常见动态内存使用错误

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

这其实也是我们平时会遇到的问题,和void*类型一样,我们不能对NULL进行加减,解引用等操作,否则系统就会报错

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导致内存泄漏

int main()
{
    while(1)
    {
        int*p=malloc(10);//不断向堆区索要空间,最终堆的空间会枯竭
    }
    return 0;
}    

4.只free掉一部分动态内存开辟的空间

void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}

5.对同一块空间多次free

void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}

6.对非动态内存空间进行free

void test()
{
int a = 10;
int *p = &a;
free(p);
}

总结

在使用动态内存中,我们需要额外注意内存泄漏以及以上常见错误,不然程序跑起来可能会有很多bug

希望本篇博客对大家有所帮助,希望大家多多支持,我也会继续努力滴。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值