内存管理
1. 什么是动态内存
就是开辟在堆上的内存,而且要用特定的函数去开辟,我们常用的是malloc,和free(释放空间)
返回一个内存块给用户,返回成功就是那块空间的起始地址,失败就是NULL。
free释放空间,参数就是之前获取返回值的指针变量。
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <windows.h> #define N 10 int main() { int *p = (int*)malloc(sizeof(int)*N); //动态开辟空间 if (NULL == p){ return 1; } for (int i = 0; i < N; i++){ p[i] = i; } for (int i = 0; i < N; i++){ printf("%d ", i); } printf("\n"); free(p); //开辟完之后,要程序员自主释放 system("pause"); return 0; }
2. 为什么要有动态内存
1. 在技术方面,普通的空间申请,都是在全局或者栈区,全局一般不太建议大量使用,而栈空间有限,那么如果一个应用需要大量的内存空间的时候,需要通过申请堆空间来支持基本业务。
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <windows.h> #define N 10 int main() { char a[1024 * 1024]; //就简单的1M空间,程序就崩溃了 system("pause"); return 0; }
2. 在应用方面,程序员很难一次预估好自己总共需要花费多大的空间。想想之前我们定义的所有数组,因为其语法约束,我们必须得明确"指出"空间大小.但是如果用动态内存申请(malloc),因为malloc是函数,而函数就可以传参,也就意味着,我们可以通过具体的情况,对需要的内存大小进行动态计算,进而在传参申请,提供了很大的灵活性
、
3. 栈、堆和静态区
我们发现地址从上到下依次增大,而且堆区(heap addr)和栈区差距巨大,也就是说中间有巨大的漏空(堆区向上增长,栈区向下增长)(也就是我们图中所看到的)。
问一个问题:在C语言中,为何一个临时变量,使用static修饰之后,它的生命周期变成全局的了?
编译的时候被编译进了全局数据区。(全局特性,但是注意作用域还是不变,只是生命周期是整个程序的生命周期)
PS:栈区随着申请与释放而进行空间管理,而其他的区,基本上都是随着整个程序的运行而一直存在。
4.
4.1. 常见的内存错误
1.指针没有指向一块合法的内存
2.为指针分配的内存太小
3.内存分配成功,但并未初始化
4.内存越界(越界是一个很严重的问题,但不是所有严重的问题都会表现出来 )
5.内存泄漏
4.1. 注意
assert称为断言,如果内部条件不满足,就会报错,满足就什么都不做。但是一般用if,因为如果我们需要的情况是指针为NULL(默认行为)assert是解决不了的,而且assert一般只有在发布方式为 Debug下面有效,还有要是我们自己定义一个地址去指向非法行为,assert(if)也是没有办法去判断的,因为他也不知道用那个地址是不是非法的,所以我们写指针如果未直接引用,就要设置为NULL。