动态内存详解
1. 动态内存函数的介绍
1.1 malloc和free
查找函数的用法推荐网站:free - C++ Reference
malloc函数申请一块连续可用的空间
1.2 calloc
1.3 malloc和calloc的区别
1. malloc申请到的空间没有初始化,直接返回起始地址。calloc申请到的空间有初始化,会把空间初始化为0,直接返回起始地址。所以会导致malloc的效率更高一些。
2. 函数参数不同:malloc是直接开辟一块字节大小为size的空间;calloc是开辟一块num个大小为size的空间。
1.4 realloc
用法一:
此时的realloc相当于malloc的用法
用法二:
扩容
扩容的三种情况:
情况1:当后面有足够的空间可以扩容,realloc函数就会直接在原有空间的后面增加需要的空间。
情况三:当后面没有足够的空间可以扩容且整个空间里也找不到足够的连续空间,直接返回NULL。这个可以解释为什么最好用新的指针ptr接收返回值,不要用旧的指针p?
因为如果用了旧的指针p然后开辟失败了,就会让p=NULL ,这个会导致p指向的原有数据使用不了,也就是数据丢失。
2. 常见动态内存错误
2.1 对空指针的解引用
这个代码如果少了93-96行,就可能会有错误。因为p可能是空指针,会造成非法访问。
2.2 对动态开辟的空间的越界访问
100个字节,只有25个整形可以访问!
2.3 对非动态开辟内存使用free释放
局部变量a在栈区,free释放的是堆区!
2.4 使用free释放一块动态开辟内存的一部分
p指向的不再是动态开辟内存空间的起始位置!
2.5 对同一块动态内存多次释放
如果加上p=NULL ,那么free内部会先检测p是不是空指针,如果是空指针,就不会释放了,直接return。
2.6 动态开辟内存忘记释放
案例1:
案例2:
ctrl+alt+delete 快捷键出任务管理器
当我们把这个关掉之后,内存自动释放。可以理解为:内存就是当前程序申请的,申请的人都关掉程序了,内存就会释放。
3. 经典笔试题
3.1 题目一
运行Test函数会有什么样的结果?
1.p是str的临时拷贝,有自己的独立空间,当malloc开辟了一块内存空间后,把该空间的起始地址赋值给了p,但是很遗憾,出了GetMemory这个函数,str里的任然是NULL。而hello world要填入str所指向的那个空间里面,但是str指向地址为0的空间,无法解引用!
2.GetMemory这个函数内部有动态开辟内存空间,但是没有进行释放,存在内存泄漏问题。
改正后:
3.2 题目二
运行Test函数会有什么样的结果?
返回栈空间地址的问题
str拿到了字符串首元素h的地址,但是出了函数GetMemory之后,p就销毁了,根本找不到"hello world",所以打印的东西是未知的!
改正后:
3.3 题目三
运行Test函数会有什么样的结果?
存在动态内存开辟,没有释放指针!
改正后:
3.4 题目四
运行Test函数会有什么样的结果?
free(str)之后,str指向的那个变量里的内容的使用权限还给操作系统了,此时的str是野指针!
改正后:
4. 柔性数组
4.1 柔性数组的特点
1. 结构中的柔性数组成员前面必须至少一个其他成员
2. sizeof 返回的这种结构大小不包括柔性数组的内存
3. 包含柔性数组成员的结构用malloc()函数进行动态内存分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。