动态内存分配的基本步骤
-
使用malloc 类的函数分配内存
-
使用分配的内存进行数据操作
-
使用free函数来释放内存
malloc 和free函数必须是成对出现的 建议在free之后将指针赋值为NULL
int* p = (int*)malloc(sizeof(int));
*p = 5;
cout << *p << endl;
free(p);
内存泄漏
不再使用的已分配的内存没有将其释放称为内存泄漏
内存泄漏:
1. 丢失了内存地址(分配内存的起始地址)
2. 应该调用free而没有调用(隐式内存泄漏)
丢失了内存地址:
新建了指针类型的变量p, p在栈上,其分配的内存空间在堆上。然后对分类的内存空间进行数据填充,到此一切正常。然后程序由分配了一个内存空间,这块内存空间也有变量p指向了,这时候p原先指向的内存空间就没有指向性了,没有办法在对其进行free操作。后续操作的free是对后来重新分配的内存空间的释放。第一次分配的内存空间就丢掉了地址
&(*p) 表示p指向的内存空间的地址
&p 表示变量p本身的内存地址
int* p = (int*)malloc(sizeof(int));
cout << &(*p) << endl;//0x7fa9b96040a0
p = (int*)malloc(sizeof(int));
cout << &(*p) << endl;//0x7fa9b96040b0
动态内存分配函数
-
malloc 从堆上分配内存
原型: void* malloc(size_t) 示例: int* p = (int*)malloc(sizeof(int)); if(p != NULL){ //指针没有问题 }else{ //分配失败 } 说明: 1. 返回值是void*指针类型,需要转换 2. 由于此函数对分配的内存不进行初始化工作,因此分配的内存中可能存在垃圾数据
-
realloc 在之前分配好的内存上进行缩减或者扩容
原型: void* realloc(void* pterosaur's,size_t size); 示例: char* string1 = (char*)malloc(sizeof(char)*10); strcpy(string1,"hellowrold"); printf("%p,%s\n",string1,string1); //0x7ff92d604100,hellowrold char* string2 = (char*)realloc(string1,8); printf("%p,%s",string2,string2); 0x7ff92d604100,hellowrold 说明: 1. 使用已经拥有的内存空间并对其进行缩减或者扩容 2. 扩容的时候,如果扩容的大小在原有的内存空间由足够的未使用空间,则在原有的内存空间进行扩容,此时两指针指向的起始内存地址是一致的。 3. 如果,原有的内存空间周边没有足够的空间进行扩容,那么需要新开辟一块内存空间来存放原有的空间和需要扩容的空间。此时两个指针指向的起始内存地址就是两个不同的地址。 4. 总之,周边内存足够原址扩容,周边内存不足重新选址分配空间
-
calloc 从堆上分配内存并清零
原型: void* calloc(size_t numElements,size_t elelemtSize); 示例: int* p = (int*)calloc(5,sizezof(int)); 说明: 1. calloc会将分配的内存空间进行清零操作。因此会比malloc函数慢一些 2. calloc函数参数: 元素的个数,元素的大小,上例中表示5个int大小的空间被分配
-
free 将内存进行释放
原型: void free(void* ptr) 示例: in t* p = (int*)malloc(sizrof(int)*19); .... free(p); p = NULL; 说明: 1. 对同一块内存空间,只可以释放一次,即free只能调用一次。重复调用(重复释放)会导致程序异常 2. 通常将释放内存空间之后的指针置为NULL
迷途指针
迷途指针只的是,内存空间已经被释放了,但是指针还在指向这个已经被释放了的内存空间
,即指针没有指向有效的对象。