目录
1.malloc函数
首先我们看一下该函数的声明:
这个函数就是向操作系统申请一块连续可用的空间单位是字节并返回申请空间的地址。
2.free函数
该函数通常与可以申请动态内存的函数配套使用,功能就是把申请的空间还给操作系统如果传入的是空指针不进行任何操作。
注意:我们将该块空间还给操作系统后该空间的地址还是存在的只是我们没有访问的权限了,因为我们把使用权还给操作系统了,如果我们free之后,该块空间可能会存储其他东西,也就是说我们free之后,该块空间的指针变成了野指针,我们需要手动将其置为空指针。
如果我们不释放申请的空间就会造成内存泄漏。
3.malloc与free的代码演示
malloc与free在使用时都要包含头文件stdlib.h
如上代码就是申请了20个字节大小的内容
我们调试一下来看一下
画圈的就是我们申请的内存。
这就是大概动态内存分配函数使用的大概模式。
4.calloc函数
函数的功能是为
num
个⼤⼩为
size
的元素开辟⼀块空间,并且把空间的每个字节初始化为0。
•
与函数
malloc
的区别只在于
calloc
会在返回地址之前把申请的空间的每个字节初始化为全
0。
基本上与malloc一致最后都要释放内存
5.realloc函数
realloc函数的出现让动态内存管理更加灵活。
•
有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的时
候内存,我们⼀定会对内存的⼤⼩做灵活的调整。那
realloc
函数就可以做到对动态开辟内存⼤
⼩的调整。
函数原型如下:
如果传入空指针就相当于malloc函数如下图所示
在内存调整时分两种情况
1.内存足够:直接在后面追加就行返回的还是原来空间的地址
2.内存不足:会先在堆空间额外开辟一块空间,并将原空间的数据拷贝过来,然后把原空间释放,最后返回的是新空间的地址。
6.动态内存分配易出现的问题
1.对NULL指针的解引⽤操作
这里我们无法判断是否申请成功如果失败就是空指针就无法解引用
2.对动态开辟空间的越界访问
其中当i=10时就越界访问了
3.对⾮动态开辟内存使⽤free释放
只有动态开辟的内存可以free上面显然就是不行的
4.使⽤free释放⼀块动态开辟内存的⼀部分
p++回导致开辟的内存不是指向起始位置这样也是不行的
5.对同⼀块动态内存多次释放
多次释放也是错误的
6.动态开辟内存忘记释放(内存泄漏)
动态开辟的空间都是在堆上开辟的如果不释放总有用完的时候就会导致内存泄漏。
7.柔性数组
1.柔性数组的特点
柔性数组就是一个根据自己需求控制数组大小的数组。它是一个结构体最后的一个成员
以上两种都是可以的就是看不同的编译器
•
结构中的柔性数组成员前⾯必须⾄少⼀个其他成员。
•
sizeof 返回的这种结构⼤⼩不包括柔性数组的内存。
•
包含柔性数组成员的结构⽤malloc ()函数进⾏内存的动态分配,并且分配的内存应该⼤于结构的⼤
⼩,以适应柔性数组的预期⼤⼩。
我们可以看一下有柔性数组的结构体的内存大小
可以看到是不计算最后的数组的大小的
2.柔性数组的使用
下面还有一种
以上都是实现相同的功能
8.总结C/C++中程序内存区域划分
其中的数据段就是我们常说的静态区
1.
栈区(stack):在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时
这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内
存容量有限。 栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等。
2.
堆区(heap):⼀般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配⽅
式类似于链表。
3.
数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
4.
代码段:存放函数体(类成员函数和全局函数)的⼆进制代码。
我们动态申请的内存都是在堆上开辟的啊~