目录
1.为什么要有动态内存分配
2.malloc、calloc、realloc和free
malloc:
calloc:
realloc:
free:
3.常见的动态内存的错误
3.1:对NULL指针的解引用操作
3.2:对动态开辟空间的越界访问
3.3:对非动态开辟的内存使用free函数释放
3.4:使用free释放一块动态开辟内存的一部分
3.5:对同一块动态内存多次释放
3.6:动态开辟内存忘记释放(内存泄漏)
4.柔性数组
柔性数组的特点
柔性数组的优势
5.总结C/C++中程序内存区域划分
我们已经掌握的内存开辟方式有:
int a = 20; ——在栈空间上开辟四个字节
char arr[100] = {0}; ——在栈空间上开辟100个字节的连续空间
其他如“double x = 1.0”、“int arr[50] = {0}”等内存开辟方式本质上跟上面两种是相同的。
那么我们既然已经有了上述两种开辟内存的方式,为什么还要开辟动态内存呢?
这就引出了我们的下文:
1.为什么要有动态内存分配
上文中我们已经讲过了我们已经掌握的两种内存开辟方式,它们有两个特点:
- 空间开辟大小是固定的
- 数组在申明时必须指定数组长度,数组大小一旦确定了就不能调整
但是上面往往不能满足我们对于空间的需求,有时候我们需要申请的空间大小往往在运行时才能知道,那数组在编译时开辟空间的方式就无法满足我们的需求了。
因此C语言引入了动态内存开辟,让我们可以自己申请开辟、调整和释放空间。
2.malloc、calloc、realloc和free
注:以下四个函数都需要包含头文件<stdlib.h>.
malloc:
C语言提供了一个动态开辟内存的函数:malloc
函数原型如下(malloc - C++ Reference (cplusplus.com)):
这个函数向内存申请了一块连续可用的空间,并返回指向这块空间的指针。
如图:
- 如果开辟成功,则返回⼀个指向开辟好空间的指针。
- 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者自己来决定
- 如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器。
calloc:
C语言还提供了一个动态开辟内存的函数:calloc
函数原型如下(calloc - C++ Reference (cplusplus.com)):
- 函数的作用是为num个大小为size的元素开辟一块空间,并把空间的每个字节都初始化为0
- 与函数malloc的区别只在于calloc在返回地址之前会把每个字节都初始化为0
因此,我们可以将calloc当作malloc使用,特别是在申请的空间要求初始化时最好用calloc。
realloc:
realloc函数就是用来对动态开辟内存的大小进行调整的。
函数原型如下(realloc - C++ Reference (cplusplus.com)):
- ptr 是要调整的内存地址(即动态开辟内存后返回的地址)
- size为调整之后的新大小(单位为字节)
- 返回值为调整之后的内存起始位置
- 原有空间之后有⾜够⼤的空间
- 原有空间之后没有⾜够⼤的空间
如图:
free:
free函数就是用来对“动态内存”进行释放和回收的。
函数原型如下(free - C++ Reference (cplusplus.com)):
- 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。
- 如果参数 ptr 是NULL指针,则函数什么事都不做。
注意:free是对“动态”内存进行释放的,而且释放后我们需要将释放的指针置NULL以规避野指针。
3.常见的动态内存的错误
3.1:对NULL指针的解引用操作
如图:
3.2:对动态开辟空间的越界访问
如图:
当运行时程序会报错。
3.3:对非动态开辟的内存使用free函数释放
如图:
此时p指针的空间为固定的,并非动态开辟出的空间,因此不能用free释放,运行时程序会报错。
3.4:使用free释放一块动态开辟内存的一部分
如图:
一如既往的报错。
3.5:对同一块动态内存多次释放
3.6:动态开辟内存忘记释放(内存泄漏)
4.柔性数组
柔性数组概念比较小众,但它确实存在。
C99中,结构中的最后一个元素允许是未知大小的数组,这就叫柔性数组成员。
如图:
有些编译器不支持a[0]的写法,那么我们改成a[]也是可以的,如图:
柔性数组的特点
- 结构中的柔性数组成员前⾯必须⾄少有⼀个其他成员。
- sizeof 返回的这种结构大小不包括柔性数组的内存。
- 包含柔性数组成员的结构用malloc ()函数进⾏内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
柔性数组的优势
如图:
5.总结C/C++中程序内存区域划分
- 栈区(stack):在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时 这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内 存容量有限。 栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等。
- 堆区(heap):⼀般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。
- 数据段(静态区):(static)存放全局变量、静态数据。程序结束后由系统释放。
- 代码段:存放函数体(类成员函数和全局函数)的⼆进制代码。
创作不易,如果觉得作者写的勉强能入眼的话给个免费的三连吧亲😙