目录1. malloc 和 free1.1 malloc编辑1.2 free2. calloc 和 realloc2.1 calloc2.2 realloc3. 常见动态分配错误3.1 未判断NULL3.2 越界访问3.3 free了非动态内存编辑3.4 free了部分动态内存3.5 重复free同一内存3.6 内存泄漏4. 柔性数组5. 总结使用动态内存要添加头文件stdlib.h作用程序员可以自己申请和开辟空间更加灵活。动态内存存放在内存堆区1. malloc 和 free1.1 malloc作用申请一块连续可用的空间并返回指向这个空间的指针。void* malloc (size_t size);*注意size单位是字节返回值使用示例存什么数据就用什么类型需要强制类型转换1.2 free作用释放回收指向的动态内存。void* free (void* ptr);ptr具体指向的是动态内存块的起始地址。常见误区在释放内存后一定要置NULL !!!!!!2. calloc 和 reallocCiallo(∠・ω )⌒★2.1 calloc作用将申请的动态内存空间的每个字节初始化为0。void* calloc (size_t num, size_t size);2.2 realloc作用扩大/缩小动态分配的内存块。void* realloc (void* ptr, size_t size);*注意事项realloc在调整内存大小时存在两种情况原有空间足够大扩容时直接在原内存后追加内存返回原来的 ptr 。原有空间不足时寻找新空间拷贝原有数据至新空间释放原有空间返回新空间起始地址因为realloc可能返回NULL因此我们需要先用一个临时指针接收返回值再判断要不要赋值给原指针上图代码2相比代码1更加安全。3. 常见动态分配错误3.1 未判断NULL3.2 越界访问//动态开辟的内存也存在边界越界算是老生常谈的问题了3.3 free了非动态内存3.4 free了部分动态内存//只能free整块动态内存因为malloc在开辟空间时会在内存块开头记录这块内存的大小信息如果ptr指向的不是起始地址free就不知道空间的大小了。3.5 重复free同一内存// free 完记得对 ptr 置 NULLeg1void test() { int* p (int *) malloc(100); free(p); free(p); //重复释放 }eg2// 在自定义函数内部和主函数中各自 free 了一次int* test() { int*p (int*) malloc(100); if(p NULL) return NULL; free(p); //释放 return p; } int main() { int* r test(); free(r); //再次释放 return 0; }因此要养成free 后及时置 NULL的习惯。3.6 内存泄漏在扩容后没有释放内存是很危险的因此要主动free掉开辟的内存否则程序结束时内存才会释放被动。4. 柔性数组定义结构体中的最后一个元素大小未知包括0的数组struct st_type { int t; int a[]; //或者a[0] }特点eg优点方便内存释放减少free使用提升访问速度分多次扩容会导致内存分布很散5. 总结在C / C中内存区域划分如下图所示栈区存放局部变量函数参数等等堆区存放动态开辟的内存分配方式类似链表数据域 指针域数据段静态存放全局变量和静态数据static代码段存放常量和可执行代码需要置NULL的情况free 后的指针指向同一块已经free了的内存的多个指针assert的使用场景在mallloc开辟内存后检查在callloc开辟内存后检查在realloc扩大 / 缩小后检查使用自定义函数时检查传入指针// 感谢阅读~(❁´◡❁)
C语言:动态内存管理
目录1. malloc 和 free1.1 malloc编辑1.2 free2. calloc 和 realloc2.1 calloc2.2 realloc3. 常见动态分配错误3.1 未判断NULL3.2 越界访问3.3 free了非动态内存编辑3.4 free了部分动态内存3.5 重复free同一内存3.6 内存泄漏4. 柔性数组5. 总结使用动态内存要添加头文件stdlib.h作用程序员可以自己申请和开辟空间更加灵活。动态内存存放在内存堆区1. malloc 和 free1.1 malloc作用申请一块连续可用的空间并返回指向这个空间的指针。void* malloc (size_t size);*注意size单位是字节返回值使用示例存什么数据就用什么类型需要强制类型转换1.2 free作用释放回收指向的动态内存。void* free (void* ptr);ptr具体指向的是动态内存块的起始地址。常见误区在释放内存后一定要置NULL !!!!!!2. calloc 和 reallocCiallo(∠・ω )⌒★2.1 calloc作用将申请的动态内存空间的每个字节初始化为0。void* calloc (size_t num, size_t size);2.2 realloc作用扩大/缩小动态分配的内存块。void* realloc (void* ptr, size_t size);*注意事项realloc在调整内存大小时存在两种情况原有空间足够大扩容时直接在原内存后追加内存返回原来的 ptr 。原有空间不足时寻找新空间拷贝原有数据至新空间释放原有空间返回新空间起始地址因为realloc可能返回NULL因此我们需要先用一个临时指针接收返回值再判断要不要赋值给原指针上图代码2相比代码1更加安全。3. 常见动态分配错误3.1 未判断NULL3.2 越界访问//动态开辟的内存也存在边界越界算是老生常谈的问题了3.3 free了非动态内存3.4 free了部分动态内存//只能free整块动态内存因为malloc在开辟空间时会在内存块开头记录这块内存的大小信息如果ptr指向的不是起始地址free就不知道空间的大小了。3.5 重复free同一内存// free 完记得对 ptr 置 NULLeg1void test() { int* p (int *) malloc(100); free(p); free(p); //重复释放 }eg2// 在自定义函数内部和主函数中各自 free 了一次int* test() { int*p (int*) malloc(100); if(p NULL) return NULL; free(p); //释放 return p; } int main() { int* r test(); free(r); //再次释放 return 0; }因此要养成free 后及时置 NULL的习惯。3.6 内存泄漏在扩容后没有释放内存是很危险的因此要主动free掉开辟的内存否则程序结束时内存才会释放被动。4. 柔性数组定义结构体中的最后一个元素大小未知包括0的数组struct st_type { int t; int a[]; //或者a[0] }特点eg优点方便内存释放减少free使用提升访问速度分多次扩容会导致内存分布很散5. 总结在C / C中内存区域划分如下图所示栈区存放局部变量函数参数等等堆区存放动态开辟的内存分配方式类似链表数据域 指针域数据段静态存放全局变量和静态数据static代码段存放常量和可执行代码需要置NULL的情况free 后的指针指向同一块已经free了的内存的多个指针assert的使用场景在mallloc开辟内存后检查在callloc开辟内存后检查在realloc扩大 / 缩小后检查使用自定义函数时检查传入指针// 感谢阅读~(❁´◡❁)