动态内存管理

引言:

学习到现在,我们开辟内存的方式有两种:要么创建一个变量,要么用数组开辟一块连续的空间。但是这两种方式一旦申请之后是不能改变大小的,因此这样的方式是有缺点的。C语言中引入了动态内存管理的方式,程序员可以自己申请和释放空间,如果觉得不够用可以再扩大,让内存分配更加灵活。

强调:通过动态内存管理的方式开辟(malloc,calloc,realloc)的空间是在堆区上的

一.malloc函数

动态内存管理_第1张图片

malloc包含在的头文件中,它有一个参数size,表示要申请的空间的大小,单位是字节。返回一个指向该空间的无具体类型的指针。 如果开辟失败,则返回NULL

所以我们使用malloc开辟空间后要检查返回的指针是否是NULL。 

动态内存管理_第2张图片

申请好空间,里面的值是随机的,需要我们自己手动赋值。

二.free函数

动态内存管理_第3张图片 

free函数是用来释放动态开辟的空间的。参数是一个指针,这个指针必须指向动态开辟的空间的起始地址

注意: 

1.如果ptr指向的空间不是动态开辟的,那么free函数的行为是未定义的。在VS上程序会直接崩掉。

2.如果ptr为NULL,那么free函数什么也不做。

3.free释放空间后,要及时把ptr置为NULL,否则就会成为野指针。

动态内存管理_第4张图片

三.calloc函数

动态内存管理_第5张图片 

calloc函数的功能是开辟一块num个大小为size字节的连续空间。和malloc不同的是,calloc开辟好空间后会把每个字节初始化为0.

例如:

动态内存管理_第6张图片

可以看到里面存放的数据都已经被初始化为0了。 

四.realloc函数 

动态内存管理_第7张图片

realloc函数的功能就是调整动态开辟的空间的大小。

第一个参数ptr就是动态开辟的内存的首地址,第二个参数size就是我们现在需要的新的大小。

返回一个指向新空间(可能还是原来的,可能发生变化,也有可能是NULL)的地址。 

1.如果开辟失败(比如申请的空间过大)就会返回NULL。

2.如果开辟成功,并且原来空间的后面空间足够,就还是返回原来的那个地址。

3.如果开辟成功,但是原来空间的后面空间不够扩大,realloc就会在堆区上重新找一块空间,并把旧空间的数据拷贝到新空间,释放旧空间,返回新空间的地址。

动态内存管理_第8张图片

这里我们要注意接收realloc的返回值时,我们要用一个新的指针变量来接收。因为如果返回的地址是NULL,那么我们连原来旧的空间也找不到了,这样就发生了内存泄露。 

realloc函数除了可以调整空间大小,也可以实现和malloc一样的功能。

如果给realloc传的地址是NULL,那么realloc会直接开辟一块空间。

动态内存管理_第9张图片

 

总结: malloc,calloc,realloc开辟的空间出了作用域不会销毁,因为他们在堆区开辟空间,而不是在栈区。释放的方式有两种:

1.free手动释放。

2.直到程序结束,操作系统自动回收。

五.动态开辟空间的常见错误

1.对NULL指针解引用

动态内存管理_第10张图片

因为这里申请的空间过大,大概率会开辟失败,所以直接对p解引用是不对的。应该判断是否为NULL。

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

动态内存管理_第11张图片

这样存在越界访问,一旦运行,程序会挂掉。

3.对非动态开辟的空间free释放 

动态内存管理_第12张图片

这样的错误也会导致程序挂掉。

4.使用free释放动态内存的一部分

动态内存管理_第13张图片 

 

5.动态开辟内存忘记释放(内存泄漏) 

动态内存管理_第14张图片

忘记释放就会导致这块空间无法再使用,只能等到程序结束,由操作系统自动回收。 

 

六.柔性数组

在结构体中最后一个成员允许是未知大小的数组(该数组前面至少有一个其他成员)

例如:

动态内存管理_第15张图片 

sizeof计算这种结构体大小时,不包括柔性数组的大小。 

动态内存管理_第16张图片

对此,开辟这种结构体空间时,我们可以采用动态开辟的方式。

动态内存管理_第17张图片 

需要多大的空间我们就开辟多大的空间,如果后续使用中不够,可以用realloc来调整数组的大小,所以这种柔性数组的大小是可变化的。 

 除了用柔性数组,我们还可以通过链表的方式来实现可变大小的数组。

动态内存管理_第18张图片

 

对比这两种方案,柔性数组的方式更加好一些。

1. 因为链表需要malloc两次,这样我们忘记free的可能性就会增大。

2.链表的方式容易出错,在上面的例子中,我们必须要先释放arr,再释放p。如果反了,就会导致arr找不到那块空间,导致内存泄露。

3.柔性数组使空间更加集中在一起,防止了内存碎片化,根据局部性原理,可以提高程序运行的速度。

本节内容结束!感谢观看。

请大家多多支持,点赞加关注!

 

 

你可能感兴趣的:(数据结构,c语言,visualstudio,算法)