为什么要有动态内存分配?
申请内存我们可以创建变量,例如:int n = 10;(申请了4个字节的空间)、char arr[20];(申请了20个字节的空间),但是用上面的申请方式,一旦创建好空间,大小就无法调整。再例如描述一个班的成绩:int score[30];,如果只有25人,空间就会浪费,有35人,空间不够。于是C/C++给了权限让程序员动态申请空间。
动态内存分配的四个函数
malloc函数
使用需包含头文件<stdlib.h>,参数是size_t size,返回类型是void*(只告诉了申请多少字节,数据类型不可知,所以返回void*),size的单位是字节,申请多大的空间,size传多少。
这个函数向内存申请一块连续可用的空间,并返回这块空间的起始地址。
如果空间开辟成功,返回一个指向开辟好空间的指针;如果空间开辟失败,返回一个NULL指针,因此malloc的返回值一定要做检查。
注:如果size为0,malloc的行为是标准未定义的,取决于编译器。
申请的空间之后还得还回去,于是引入free函数。
free函数
做动态内存的释放和回收,使用需包含头文件<stdlib.h>,原型如下:
void free(void*ptr);要释放哪块空间,就传哪块空间的起始地址。
如果参数ptr指向的空间不是动态开辟的,那么free函数的行为是未定义的;
如果参数ptr是NULL指针,则函数什么都不做。
注:free函数是将开辟的空间的使用权限还给操作系统,我们没有访问权限,p还指向这块空间,一旦free之后,p就变成了野指针,所以给p赋一个空指针。
这样写是错误的,因为p已经走了很远,不再指向这块空间的起始地址,没法释放。
calloc函数
也用来动态内存分配,原型如下:
void*calloc(size_t num,size_t size);
函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0;
与malloc函数的区别只在于calloc函数会在返回地址之前把申请空间的每个字节初始化为0.
realloc函数
让内存管理更加灵活,有时我们会发现过去申请的空间太大/太小,为了合理使用内存,我们会对内存的大小做一个灵活地调整,realloc函数就可以做到对动态开辟的内存大小进行调整。
原型如下:
void*realloc(void*ptr,size_t size);
ptr是要调整的内存的地址,size为调整之后新的大小,返回值为调整之后内存的起始位置。
realloc函数调整分为两种情况:
情况一后面空间足够,直接将20个字节续上,返回整个空间的起始地址;
情况二后面空间不够,在堆区内存中再找一块区域,一次满足四十个字节的大小,原来的数据拷贝一份到新的空间,释放旧的空间,返回新的空间的起始地址。
极端情况情况3:空间调整失败,返回NULL
realloc函数可以完成和malloc一样的功能:第一个参数传NULL,没法调整空间,直接创建新的空间