动态内存分配
一、C语言内存分配
一、malloc
1、按字节分配内存空间,分配的内存空间不初始化
2、返回类型为void*
3、函数只有一个参数
原型:void* malloc(size_t size);//size是字节个数
一、C语言内存分配
一、malloc
1、按字节分配内存空间,分配的内存空间不初始化
2、返回类型为void*
3、函数只有一个参数
原型:void* malloc(size_t size);//size是字节个数
二、calloc
1、按字节分配内存空间,分配的内存空间进行初始化为0
2、返回类型为void*
3、函数有二个参数,按类型字节大小和个数开辟内存空间
原型:void* malloc(size_t count,size_t size);//count是个数,size是类型大小
1、按字节分配内存空间,分配的内存空间进行初始化为0
2、返回类型为void*
3、函数有二个参数,按类型字节大小和个数开辟内存空间
原型:void* malloc(size_t count,size_t size);//count是个数,size是类型大小
三、realloc
1、动态调整内存大小
2、按字节调整内存大小
2、返回原类型void* void* realloc(void* ptr,size_t newsize);//ptr所要开辟内存的指针,newsize开辟的字节数
3、函数有二个参数,调整内存空间的指针和所要调整的大小
4、当原指针为空时,同于malloc开辟内存空间
5、当原指针不为空时,
(1)指针处有足够的的内存空间,则直接进行扩容,增大内存空间,原指针地址不变
(2)指针处无足够的内存空间,则重新寻找一块足够的内存空间,并把数据拷到新空间中,释放就旧空间,返回新空间地址。原指针地址发生改变
(3)无足够内存空间返回NULL,数据据丢失。所以建议不要使用原指针接收返回的地址,而用临时指针接收返回的地址,空间开辟成空(非NULL),再指向临时指针
防止数据丢失。
1、动态调整内存大小
2、按字节调整内存大小
2、返回原类型void* void* realloc(void* ptr,size_t newsize);//ptr所要开辟内存的指针,newsize开辟的字节数
3、函数有二个参数,调整内存空间的指针和所要调整的大小
4、当原指针为空时,同于malloc开辟内存空间
5、当原指针不为空时,
(1)指针处有足够的的内存空间,则直接进行扩容,增大内存空间,原指针地址不变
(2)指针处无足够的内存空间,则重新寻找一块足够的内存空间,并把数据拷到新空间中,释放就旧空间,返回新空间地址。原指针地址发生改变
(3)无足够内存空间返回NULL,数据据丢失。所以建议不要使用原指针接收返回的地址,而用临时指针接收返回的地址,空间开辟成空(非NULL),再指向临时指针
防止数据丢失。
问题:realloc若所要开辟的内存空间小于原内存空间,则结果为多少?开辟0个空间则会是怎样的?
答:若指定的空间小于原空间,则空间会缩小,截除后部分的数据,返回原指针。开辟空间大小为0时,释放原空间返回NULL
答:若指定的空间小于原空间,则空间会缩小,截除后部分的数据,返回原指针。开辟空间大小为0时,释放原空间返回NULL
注:不管使用那种方式管理内存空间,都需对返回值进行判断,判断空间是否开辟成功,成功返回非NULL,失败返回NULL;
释放内存空间---->free()
开辟的内存空间只能整块释放,不可部分释放。即释放的指针与开辟空间返回的指针必须相同。
释放内存空间---->free()
开辟的内存空间只能整块释放,不可部分释放。即释放的指针与开辟空间返回的指针必须相同。
C++动态内存管理
开辟内存---->new
1、new自动计算类型大小,按个数开辟内存空间,返回类型为对应的指针类型
2、new和delete为操作符不为函数
3、new和delete的底层是使用malloc和free实现的。
开辟内存---->new
1、new自动计算类型大小,按个数开辟内存空间,返回类型为对应的指针类型
2、new和delete为操作符不为函数
3、new和delete的底层是使用malloc和free实现的。
使用方法:
开辟一个int类型的空间
p1 = new int; --------------->delete p1
开辟一个int类型的空间,初始化为1
p2 = new int(1); ------------>delete p2
开辟3个int类型对象的空间,注次数是调用3次构造函数,最终也会调用3次析构函数
p3 = new int[3]; ------------>delete []p3
new 类型[] 开辟内存空间时会多开辟4个字节的空间,用于在头部保存开辟内存空间的个数,返回时向后偏移4个字节的空间,析构时会再向前偏移4个字节释放空间。
所以delete释放空间时,必须与new开辟的方法对应,否则会因空间释放位置不正确导致出错。
new和free也不可混用,否则可能会出现内存泄露的危险
因为:对于自定义类型的对象,在定义时会调用构造函数进行初始化。销毁时会调用析构函数进行销毁。
析构时会先清理类内部成员的空间,后释放对象空间,防止内存泄露。若使用free释放空间,则可能由于类内部成员空间未释放,导致内存泄露
因为:对于自定义类型的对象,在定义时会调用构造函数进行初始化。销毁时会调用析构函数进行销毁。
析构时会先清理类内部成员的空间,后释放对象空间,防止内存泄露。若使用free释放空间,则可能由于类内部成员空间未释放,导致内存泄露
注:虽然使用new---->free操作内置类型不会出错,但也不要这样使用。这样容易导致误解和可读性低。
不出错是由于编译器对内置类型进行了优化,未调用构造函数,和析构函数。
其它类型接口:
void* operator new(size_t size);
void* operator new[](size_t size);
void* operator delete(void* ptr);
void* operator delete[](void* ptr);
void* operator new(size_t size);
void* operator new[](size_t size);
void* operator delete(void* ptr);
void* operator delete[](void* ptr);
注:以上函数不是重载关系,是特列
new = operator new + 构造函数 = malloc+抛异常
delete = operator delete + 析构 = free+抛异常
new = operator new + 构造函数 = malloc+抛异常
delete = operator delete + 析构 = free+抛异常
//假设开辟10个空间
new xx[10] = operator new[] + 10次构造 = malloc(sizeof(xx)*10)+抛异常
delete []_a = operator delete[] + 10次析构 = free+抛异常
new xx[10] = operator new[] + 10次构造 = malloc(sizeof(xx)*10)+抛异常
delete []_a = operator delete[] + 10次析构 = free+抛异常
空间开辟与释放方法不匹配,是否会导致出错,主要看是否会多或少释放4个字节的空间问题。会就会导致程序崩溃。
计算机判断空间或数组越界访问的方法是,多开辟几个字节的空间并初始化为某个值,如0xcccccccc,当检测到这些值被修改时,则认为越界。