动态内存管理<C语言>
在C语言学习阶段,指针、结构体和动态内存管理,是后期学习数据结构的最重要的三大知识模块,也是C语言比较难的知识模块,但是“天下无难事”,只要认真踏实的学习,也能解决,所以下文将介绍动态内存管理涉及到的一些函数以及概念。
为什么存在动态内存管理这是我们常用的用于向内存申请空间的办法,但是:
●空间开辟的空间是固定的
●数组在申明时,数组大小一旦确定,申请的内存空间不可变
在实际编写程序时,可能我们对于内存空间的需求不是固定,那么使用动态内存管理自己申请空间、自己释放空间就是一个很好的选择。
malloc和free malloc函数参数及其返回值
注意点
●返回值是void*,那么我们在实际使用时,应把它强制转化为我们需要的类型。
●与局部变量不同,开辟空间在堆区(如数组在栈区)
●malloc不会将内存空间初始化为0,这是与最大calloc区别!
●动态内存可调整(通过realloc)
使用举例:
free
函数参数及其返回值
注意点
●只能用来手动释放动态申请的空间,如果不是结果是未定义的
●释放空间后,只是将权限交还于操作系统,指针还指向着地址(悬空指针),应该手动将其置为NULL
●如果释放指针是NULL,那么什么也不做。
使用举例:
函数参数及其返回值
注意点
●开辟空间并全部初始化为0
●两个参数(num个size字节)
●其他与malloc类似
使用举例:
realloc
函数参数及其返回值
使用举例:
运行结果:
先开辟10个int字节大小空间的运行结果:
先开辟20个int字节大小空间的运行结果:
注意点
●参数size为0时,返回值是NULL,并将ptr的内存释放,这是未定义的行为,在不同的编译器上不能保证
●如果ptr参数为NULL,会动态开辟一个新的内存空间,此时realloc函数的作用等同于malloc
●这个函数调整空间时会把数据移到新的内存空间内(实际上,有一种情况不会,但是为了代码的健壮性和可移植性,我们最好这样定义)
两种情况:
①原有地址后面有足够的空间容纳调整后的空间
②原有地址后面没有足够的空间容纳调整后的空间
其实在前面的使用举例中我们已经观察到:
先开辟10个int字节大小空间的运行结果(第一种情况)
直接在原地址后面开辟新空间
先开辟20个int字节大小空间的运行结果(第二种情况)
关于参数size为0时的举例:
因为我们没有办法直接观察一块动态开辟的内存是否被释放,且这种size为0行为是未定义的,所以我们只能观察它的返回值
关于参数ptr是NULL时的情况
此时realloc等同malloc
注意:动态内存管理的4个函数都包含在<stdlib.h>中
常见的关于动态内存管理错误 1.对可能是NULL指针的引用2.对不是动态开辟的内存进行释放
1.
p虽然在GetMemory函数中开辟了内存,但是在出函数时,该地址被销毁,所以str还是NULL指针,对NULL指针进行赋值是一个未定义行为。(传值调用而没有使用传址调用)
改正(二级指针):
改正(将开辟的空间返回):
2.
GetMemory函数返回了一个地址,但是这个地址出了函数,权限已经收回给了操作系统,str接收的是一个野指针,并将它打印出来,这种行为是未定义的,可能造成错误。(说到底是栈空间返回会被销毁的问题)
我们知道只要是函数内的变量都是栈空间申请的空间,在出函数时,都会被回收,但是动态内存管理申请的空间,必须要手动释放,所以在函数中我们使用动态内存申请的地址是不会被收回的(堆区申请),所以我们尝试改正时,在函数内部使用动态内存申请,并返回。
改正:
3.
没释放空间,内存泄漏
改正:
使用了已经被释放的内存
Ongwu博客 版权声明:以上内容未经允许不得转载!授权事宜或对内容有异议或投诉,请联系站长,将尽快回复您,谢谢合作!