学习到现在,我们开辟内存的方式有两种:要么创建一个变量,要么用数组开辟一块连续的空间。但是这两种方式一旦申请之后是不能改变大小的,因此这样的方式是有缺点的。C语言中引入了动态内存管理的方式,程序员可以自己申请和释放空间,如果觉得不够用可以再扩大,让内存分配更加灵活。
强调:通过动态内存管理的方式开辟(malloc,calloc,realloc)的空间是在堆区上的
malloc包含在
所以我们使用malloc开辟空间后要检查返回的指针是否是NULL。
申请好空间,里面的值是随机的,需要我们自己手动赋值。
free函数是用来释放动态开辟的空间的。参数是一个指针,这个指针必须指向动态开辟的空间的起始地址
注意:
1.如果ptr指向的空间不是动态开辟的,那么free函数的行为是未定义的。在VS上程序会直接崩掉。
2.如果ptr为NULL,那么free函数什么也不做。
3.free释放空间后,要及时把ptr置为NULL,否则就会成为野指针。
calloc函数的功能是开辟一块num个大小为size字节的连续空间。和malloc不同的是,calloc开辟好空间后会把每个字节初始化为0.
例如:
可以看到里面存放的数据都已经被初始化为0了。
realloc函数的功能就是调整动态开辟的空间的大小。
第一个参数ptr就是动态开辟的内存的首地址,第二个参数size就是我们现在需要的新的大小。
返回一个指向新空间(可能还是原来的,可能发生变化,也有可能是NULL)的地址。
1.如果开辟失败(比如申请的空间过大)就会返回NULL。
2.如果开辟成功,并且原来空间的后面空间足够,就还是返回原来的那个地址。
3.如果开辟成功,但是原来空间的后面空间不够扩大,realloc就会在堆区上重新找一块空间,并把旧空间的数据拷贝到新空间,释放旧空间,返回新空间的地址。
这里我们要注意接收realloc的返回值时,我们要用一个新的指针变量来接收。因为如果返回的地址是NULL,那么我们连原来旧的空间也找不到了,这样就发生了内存泄露。
realloc函数除了可以调整空间大小,也可以实现和malloc一样的功能。
如果给realloc传的地址是NULL,那么realloc会直接开辟一块空间。
总结: malloc,calloc,realloc开辟的空间出了作用域不会销毁,因为他们在堆区开辟空间,而不是在栈区。释放的方式有两种:
1.free手动释放。
2.直到程序结束,操作系统自动回收。
因为这里申请的空间过大,大概率会开辟失败,所以直接对p解引用是不对的。应该判断是否为NULL。
这样存在越界访问,一旦运行,程序会挂掉。
这样的错误也会导致程序挂掉。
忘记释放就会导致这块空间无法再使用,只能等到程序结束,由操作系统自动回收。
在结构体中最后一个成员允许是未知大小的数组(该数组前面至少有一个其他成员)
例如:
sizeof计算这种结构体大小时,不包括柔性数组的大小。
对此,开辟这种结构体空间时,我们可以采用动态开辟的方式。
需要多大的空间我们就开辟多大的空间,如果后续使用中不够,可以用realloc来调整数组的大小,所以这种柔性数组的大小是可变化的。
除了用柔性数组,我们还可以通过链表的方式来实现可变大小的数组。
对比这两种方案,柔性数组的方式更加好一些。
1. 因为链表需要malloc两次,这样我们忘记free的可能性就会增大。
2.链表的方式容易出错,在上面的例子中,我们必须要先释放arr,再释放p。如果反了,就会导致arr找不到那块空间,导致内存泄露。
3.柔性数组使空间更加集中在一起,防止了内存碎片化,根据局部性原理,可以提高程序运行的速度。
本节内容结束!感谢观看。
请大家多多支持,点赞加关注!