分配内存的函数
malloc
void* malloc(size_t size);
如果开辟成功,则返回一个指向开辟好空间的指针
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
如果参数size为0,malloc的行为是标准是未定义的,取决于编译器
free
void free(void* ptr);
如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的
如果参数ptr是NULL指针,则函数什么事都不做
calloc
void* calloc(size_t num, size_t size);
函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0
realloc
void* realloc(void* ptr, size_t size);
如果size比原来小,则前size个字节不变,后面的数据被截断,如果size比原来大,则原来的数据全部保留,这里存在两种情况:
情况1:原有空间之后有足够大的空间,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化
情况2:原有空间之后没有足够大的空间,在堆空间上另找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址
如果参数ptr是空指针,则类似malloc,返回指向开辟好空间的指针
如果参数size为0,则类似free,返回空指针
alloca
void* alloca(size_t size);
参数size是请求分配的字节数,返回所分配内存空间的首地址,如果size太大导致栈空间耗尽,结果是未定义的,alloca函数不是在堆上分配空间,而是在调用者函数的栈帧上分配空间,类似于C99的变长数组,当调用者函数返回时自动释放栈帧,所以不需要free。这个函数不属于C标准库,而是在POSIX标准中定义的
定义一个不易发生错误的内存分配器
1 | // alloc.h |
柔性数组
C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员
1 | typedef struct st_type { |
柔性数组的特点
结构中的柔性数组成员前面必须至少一个其他成员
sizeof返回的这种结构大小不包括柔性数组的内存
包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小
柔性数组的优点
- 方便内存释放,把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉,不用担心结构体内的成员也需要free
- 利于访问速度,连续的内存有益于提高访问速度,也有益于减少内存碎片
new/delete操作符
操作:new data-type;
data-type可以是包括数组在内的任意内置类型数据,也可以是自定义的任何数据类型
如:int* p = new int(3); delete p;
在堆上申请空间,创建对象int并初始化为3int* p = new int[3]; delete[] p
在堆上申请3个int大小空间,创建3个对象
new
new底层调用先operator new函数申请空间,然后执行构造函数,完成对象的构造
operator new底层调用malloc,当malloc申请空间成功时直接返回;申请空间失败尝试执行应对措施,若无应对措施则抛异常
delete
先在空间上执行析构函数,完成对象中资源的清理工作,调用operator delete函数释放对象的空间
new T[N]
先调用operator new[](在operator new[]中实际调用operator new函数完成N个对象空间的申请)然后在申请的空间上执行N次构造函数
delete[]
先在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
然后调用operator delete[]释放空间(在operator delete[]中调用operator delete来释放空间)
定位new表达式
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象Type* ptr = (Type*)malloc(sizeof(Type)); new(ptr) Type;
如果构造函数有参数,需传参