动态内存管理 干货2
目录
七.常见的动态内存的错误
1.对空指针进行解引用操作。
2.对动态开辟空间的越界访问
3.对非动态开辟的内存使用free释放
4.动态开辟内存忘记释放,造成内存泄漏!!
八.动态内存经典笔试题
1.
2.
3.
九.柔性数组
小伙伴们,看本篇文章之前,可以先去看我的博客里的“动态内存管理 干货1”,再看这篇!!
七.常见的动态内存的错误
1.对空指针进行解引用操作。
上篇文章有讲到其中一个比较重要的步骤就是:要判断返回值是否是空指针。如果你没有对返回值进行是否是NULL的判断,直接进行解引用操作,编译器会怀疑这个变量是否是NULL,会报错
2.对动态开辟空间的越界访问
3.对非动态开辟的内存使用free释放
上篇文章有讲过,free只可以对动态开辟的空间进行空间释放!!
4.动态开辟内存忘记释放,造成内存泄漏!!
这里是将malloc申请的空间赋值给p了,但是p是局部变量,只在函数内部有效,函数执行结束后,该变量所占用的内存地址会被释放,外部没办法再找到它,访问它,使用它。那么这时候想去释放空间,都找不到,那么就代表那块空间不仅没用了,还是释放不了给其他人用,相当于白白占用着空间。
重点:
malloc,calloc,realloc在申请空间后,不想使用空间了,就用free释放
如果没有使用free释放,当程序运行结束后,也会被操作系统回收和释放的。
那么有人就会问:既然操作系统会帮我们回收并释放内存,那又何必free?
操作系统不是立即回收释放的。如果你不主动用free释放,系统不会管它们,会一直占用着内存资源。只有程序结束后,系统才会将所有的内存回收,可是这期间,程序就可能因为内存不足或内存泄漏出问题。
八.动态内存经典笔试题
1.
图1
首先,102行是传值调用。(因为它传的是str本身,而不是str的地址,比如&str)
str是空指针,Getmeory将str传给p,其实就是将NULL传给p。
然后malloc申请100个字节的空间,并将这100个字节的空间的首地址传给p。
出了函数,函数执行结束后,变量p的内存空间被释放,外部就没办法再找到,访问并使用它!
所以现在回到103行,这个str里面还是NULL,但是strcpy参数部分,必须得是有效指针,指向有效地址,而NULL指向无效地址,所以程序会崩溃!!
其次就是,malloc申请内存空间后,使用完并没有free释放,可能会造成内存泄漏!!
那么,我们可以修改一下上面的代码!!(修改过程打上序号)
图2
还有一种修改方式:(修改过程打上序号)
图3
2.
图4
- 这个代码也是有问题的。因为p在函数执行结束后,内存空间会被释放,外部无法再访问和使用它。
- 那有人就会有疑惑,那图3也是return p,为什么图3的代码就是正确的?
- 因为图3中是在堆区申请内存。堆区的内存不会像栈区局部变量那样,在函数结束时会自动回收内存空间,它需要手动free释放,直到程序结束后才会自动回收并释放。但是图4中的p是局部数组变量,局部变量存储在栈区!
所以说在16行赋值之后,str里存的是字符串首元素的地址,但是有地址却访问不到它所指向的空间,因为空间已被回收,进而也就在17行打印不出来。
那么这时候,str是非法访问,并且str是野指针!!
如果是这样,返回的是一个值,这没问题。但如果返回的是地址(例如:return &n),就是错误的,因为地址的空间会被回收!
图5
3.
图6
这里的代码错误是:
60行的str里面是申请的那100个空间的首地址,61行,str里放的是hello,62行把str的空间释放了,也就是外部对str没有访问和使用权限了,但是地址依然在(hello的地址),只是空间没了。
再到下面65行,这里其实就是对str的非法访问了,world覆盖了str里原有的hello。
即:非法访问空间并篡改了内容!!
记住:空间被收回或释放的指针,极有可能成为野指针。且空间被收回或释放的指针,不可以再被外界访问并使用,因为是非法访问
九.柔性数组
1.什么是柔性数组?
- 在结构体中
- 是最后一个成员
- 并且是一个数组
- 并且该数组并未指定大小
柔性数组的特点:
- 结构体中的柔性数组成员前面必须至少有一个其他成员
- sizeof返回结构体大小不包含柔性数组的部分
- 包含柔性数组成员的结构体用malloc进行动态内存分配,分配的内存应该大于结构的大小。以适应柔性数组的预期大小
当你用malloc函数去申请空间时,也可以用realloc,这样就方便将这个数组的空间变大或变小,所以叫“柔”性数组。