重点需要知道:
1.为什么存在动态内存分配
2.动态内存函数:malloc free calloc realloc
3.常见的动态内存错误
4.几个经典的笔试题
5.柔性数组
为什么存在动态内存分配
当前我们知道的内存使用方式:
1.创建一个变量 int a=10;//局部变量 放在 栈区
int g_a=10;//全局变量 放在 静态区
栈区:局部变量 函数的形式参数
堆区:动态内存分配
静态区:全局变量,静态变量,static int a=10;
2.创建一个数组 int arr【10】;局部和全局放的地方和变量一样
假如我们想创建50个学生的数组 此时vs无法在此情况下创建数组,因为不支持括号里面为变量
但是在部分编译器可以,看编译器是否支持c99
所以我们可以用动态内存来开辟空间
我们先了解下动态内存函数
malloc 向内存申请字节
void* malloc(size_t size); 开辟失败会返回空指针 所以要做好检查
返回值由自己决定,所以强制类型转换看具体使用
free和malloc要成对使用
如果不需要这个空间却不释放空间,会一直占用这个空间,会影响到后续进程
calloc 会开辟一块空间元素为0
void*calloc(size_t num,size_t size);
calloc会初始化空间,malloc不会初始化,直接打印会是一堆随机数
realloc
void*realloc(void*memblock,size_t size)
realloc使用的注意事项
使用时会出现两种情况:1.追加的少 会自己在现在的内存后面追加
2.追加的过大,会重新开辟一块空间把值拷贝过去,释放旧的内存区域。此时地址就会发生变化
3.如果非常大,可能会开辟失败。会给予空指针,此时由于赋值给p,追加失败之后原空间也会消失。所以一般用一个新指针来接受值
用一个新变量来接受realloc,追加成功后在赋值给p
最后也要记得释放内存
常见问题
1.忘记判断是否为空指针,万一为空指针解引用会非法
2.对动态开辟内存进行越界访问(关注自己开辟的空间和实际使用空间要一致)
3.对非动态开辟内存使用free释放(比如对正常使用的int a=10;)
4.使用free释放动态开辟内存的一部分
因为此时p指向了最后一个元素,没有在指向malloc开创的第一个元素
5.对同一块动态内存多次释放(指free两次,所以free之后赋予空指针可以避免此情况)
6.动态开辟的空间忘记释放(内存泄漏)(指使用了不用之后忘记回收)
寻找下图代码问题
1.运行代码会出现崩溃 2.存在内存泄漏的问题(str以值的形式传递给了p,p是GetMemory的形参,只在函数内部有效,函数返回后,动态内存未释放且无法再找到 会有内存泄漏)
正确形式
寻找问题
返回栈空间地址的问题(数组前加上static,可以保留值)
柔性数组
C99中,结构中的最后一个元素允许是未知大小的数组,这就叫柔性数组成员
第二种写法,在结构体内用指针,就不用使用柔性数组了
柔性数组开辟的是连续的一个空间 指针是从一个内存中再指向另一个开辟的空间。
柔性数组只需释放一次空间 而且没有释放顺序 可以减少错误概率、而且malloc使用的次数少一些,内存利用率相对较高。内存是连续的,访问效率更高。