目录
一.为什么存在动态内存管理:
我们知道,在此之前向内存申请空间的方式有以下两种:(变量和数组)
但这两种方法有几个缺陷:
①:空间开辟大小是固定的;
②:数组在声明的时候,必须指定数组的长度,它所需要的内存在编译时分配;
但是由于空间的需求,不仅仅是上述两种情况,有时候我们需要的空间大小在程序运行的时候才知道,那数组的编译时开辟空间的方式就不合适了。
假设数组大小为100,但有101个元素就塞不下;只有10个元素又太浪费空间了。
所以这时候只能试试动态分配了。
二、动态内存函数的介绍:
1.动态开辟函数——malloc函数
1.1.函数声明和作用:
void* malloc (size_t size);
①:函数作用:向内存申请一块可用的连续的空间,返回值为这块空间的起始地址;
②:函数参数:类型为size_t,即该函数一次申请size个字节的空间,但不会初始化该空间内容,如果size==0,那么malloc的行为是未定义的,取决于编译器;
③:返回值是void*,返回规则如下:
④:该函数包含头文件<stdlib.h>中。
⑤:动态内存函数申请空间都是在堆区上面申请,如下图:
1.2.函数使用实例:
#include<stdio.h> #include<stdlib.h> int main() { //要什么类型的空间,就用什么类型的指针接收 //注意函数返回值为void*,所以记住强制类型转换 int* p = (int*)malloc(40); //判断申请空间是否成功 if (p == NULL) { perror("malloc");//打印申请失败的原因 return 1; } //使用空间 int i = 0; for (i = 0; i < 4; i++) { p[i] = i; printf("%d ", p[i]); } return 0; }
2.释放动态空间函数——free函数
注意:这些动态开辟函数申请内存空间,当程序退出时,会还给操作系统,但当程序不退出,动态开辟的内存不会主动释放,这时就需要用到函数free()来释放。
2.1.free函数注意事项:
、
①:函数声明:
void free (void* ptr);
②:该函数包含在头文件<stdlib.h>中。
2.2.free函数使用实例:
该函数使用方法非常简单,参数只需要给动态开辟的变量即可,如下:
这里值得注意的是,free函数释放空间后,不会改变指针p的值,所以此时p还是指向这块空间,但该空间已被释放,所以此时p是野指针,所以我们要把p指针置空。
3.动态开辟函数——calloc函数
3.1.函数的声明和作用:
void* calloc (size_t num, size_t size);
①:函数的作用:该函数是动态开辟num个大小为size的空间,并且把空间的每个字节初始化为0;
②:返回值和malloc相同,开辟成功返回这块空间的起始地址;开辟失败返回NULL。
③:与malloc函数的区别是:该函数为把空间的每个字节初始化0。
④:
3.2.函数使用实例:
int main() { //动态开辟五个整型大小的空间 int* p = (int*)calloc(5, sizeof(int)); //检查是否开辟成功 if (p == NULL) { perror("calloc"); return 1; } //使用空间 for (int i = 0; i < 5; i++) { printf("%d ", p[i]); } //释放空间 free(p); p = NULL; return 0; }
运行结果:
4.动态开辟函数——realloc(最主要、最常用):
4.1.注意事项:
realloc函数的出现让动态内存管理更加灵活。
有时我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,为了合理使用内存,我们就可以用realloc函数动态开辟内存,以便对内存的大小做灵活调整。
4.2.函数声明与作用:
void* realloc (void* ptr, size_t size);
①:参数介绍:
第一个参数void*,是指需要调整大小的空间,是之前通过malloc、calloc、realloc函数开辟好的;
第二个参数size_t szie,是指调整后的新的空间大小,单位为字节;
②:当第一个参数ptr为空指针时,效果和malloc相同。
4.3.函数返回值:有三种情况
情况一:若str后面还有足够的连续空间,则返回值为str的起始空间。
情况二:若str后面没有足够的连续空间,则realloc函数会重新找一份足够大的新空间;将旧空间的内容拷贝到新空间;然后释放掉旧空间;最后返回新空间的起始地址。
情况三:开辟失败,返回NULL。
4.4.函数使用实例:
int main() { //先用malloc开辟5个整型的空间 int* p = (int*)malloc(20); //检查malloc是否开辟成功 if (p == NULL) { perror("malloc"); return 1; } //开辟成功后,赋值1,2,3,4,5 int i = 0; for (i = 0; i < 5; i++) { p[i] = i + 1; } //用realloc扩容五个整形的空间,所以新空间为40字节 //注意这里别用上面的指针p接收, //因为如果realloc开辟失败,就会返回空指针给指针p //指针p改变了,那么之前动态开辟的空间就找不到了,就会存在内存泄漏 int* str =(int*) realloc(p, 40); //检查是否开辟成功 if (str == NULL) { perror("realloc"); return 1; } //开辟成功后再赋值给指针p,然后将str置零 p = str; str = NULL; //检测是否将旧空间的数据拷贝到新空间 for (i = 0; i < 5; i++) { printf("%d ", p[i]); } //释放 free(p); p = NULL; return 0; }
运行结果:
本次知识到此结束,关于动态内存的知识还没有结束,未完待续!