写作不易,点个赞吧铁铁,文中若有不妥之处,恳请各位读者批评指正
一、什么是动态内存管理?
一种内存管理方法。对内存空间的分配、回收等操作在进程执行过程中进行,以便更好地适应系统的动态需求,提高内存利用率。
二、为什么需要动态内存管理?
对于初学者而言,已经基本可以掌握的内存开辟方法:定义+初始化的方法。
int a=0; int arr[]={0,1,2,3}
char arr[]={"abcd"}等等
但是上述内存的开辟大小是在编译前就确定的,同时数组在声明的时候又必须指定数组长度, 它所需要的内存在编译的时候分配;【这种开辟方式的特点】
三、动态内存函数
1、malloc
定义 : void* malloc (size_t size); (stdlib.h)
作用
向内存申请一段连续的、可用的空间
特点
//返回类型为void*,参数为开辟空间的大小(单位字节)
- 这个函数向内存申请一段连续可用的空间,并返回指向这个空间的指针
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查(assert)。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己 来强制类型转换。
- 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
实例
运行结果为0 1 2 3 4
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(5 * sizeof(int));
for (int i = 0;i < 5;i++)
{
*(p + i) = i;
printf("%d ", *(p + i));
}
free(p);
p = NULL;
return 0;
}
2、free
定义void free(void*str);(stdlib.h)
作用
free是c语言提供的,专门用来释放、回收动态开辟出来的空间的函数。
特点
- 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的,运行代码的时候将会报错。
- 如果参数 ptr 是NULL指针,则使用free函数将什么事都不不会发生。
(举例同上malloc实例)
3、calloc
定义 void*calloc(size_t num,size_t size)
(stdlib.h)
作用
它的作用同malloc相似,也是向内存申请一段连续的、可用的空间。
特点
- 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
- 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0
举例
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(5 * sizeof(int));
printf("p(malloc):");
for (int i = 0;i < 5;i++)
{
printf("%d ", *(p + i));
}printf("\n\n");
int* c = (int*)calloc(5, sizeof(int));
printf("c(calloc):");
for (int i = 0;i < 5;i++)
{
printf("%d ", *(c + i));
}
printf("\n\n");
free(p);free(c);
p = NULL;c=NULL;
return 0;
}

4、realloc
void*realloc(void*p,size_t size) stdlib,h
作用
重新调整已开辟空间的大小。
realloc函数的出现让动态内存管理更加灵活。在使用malloc或者calloc函数的时候,可能会遇到动态开辟的内存仍然不够的情况,会觉得申请的空间过大或者过小,那为了合理地使用内存,避免再去重新开辟一段内存空间,造成难以维护的情况,那么将会使用到realloc函数。 realloc 函数就可以做到对动态开辟内存大小的调整。
特点
- 指针p是要调整的已经开辟的空间的地址
- size是调整后的大小(单位:字节)
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
- 在使用realloc调整动态内存的时候存在两种不同的开辟方法:
方法1、原有空间之后存在足够的且连续的空间:
方法2、在堆空间中另找一块连续的空间;
实例
int*p=(int*)malloc(5*sizeof(int));
//若空间不够了,使用realloc
int*p=(int*)realloc(p,10*sizeof(int));
四、常见动态内存错误
1、动态内存访问越界
类似于数组int arr[10]访问越界:访问了不属于它的空间。
int arr[10]; arr[11]=0;
动态内存开辟的空间同样存在越界访问的问题
案例
int i = 0;
int* p = (int*)malloc(10 * sizeof(int));
if (NULL == p)
{
exit(EXIT_FAILURE);
}
for (i = 0; i <= 10; i++)
{
*(p + i) = i;//当i是10的时候越界访问
}
free(p);
p = NULL;
2、对NULL空指针进行解引用操作
int * p = ( int * ) malloc ( INT_MAX / 4 );* p = 20 ; //如果malloc开辟空间失败,则会返回空指针(NULL),此时将空指针赋给p//解引用后就是对空指针的解引用
这种操作会引起程序或者系统崩溃
3、对非动态开辟内存使用free释放
int a=10; int*p=&a; free(p);

此操作会引起程序崩溃;
4、free未释放动态开辟的内存
1、未使用free函数
这种错误较为隐蔽,错误产生了但是不容易被发现
int *p=(int*)malloc (5*sizeof(int));//未使用free
未使用free不会报错,但是存在内存泄漏,影响程序的正常运行。
2、使用了free函数,但只释放了部分内存
int* p = (int*)malloc(5 * sizeof(int));
p++; //此处将p的地址向后挪了一位;
free(p);
p=NULL;


- 当p的所指向的位置向后移位的时候,free只释放了部分动态开辟内存,仍存在一部分内存没有被回收,也是内存泄漏的一种。 此时运行程序就会发生崩溃。
5、对一块动态开辟内存进行多次释放
int *p=(int*)malloc (5*sizeof(int)); //假设开辟成功
free(p);
free(p);

同样会报错。
解释:当你将p free释放的时候,p指向的这块空间已经不属于malloc等函数动态开辟的空间,系统可能将这块空间分配给了其他程序,这时在此使用free就相当于释放了非动态开辟内存,就会同上面一样报错。
总结
此文章讲解了什么是动态内存管理,以及一些常用的动态内存管理的函数,和常见错误
本文介绍了动态内存管理的基本概念,包括malloc、calloc、realloc和free等函数的用法,阐述了动态内存管理的必要性,并列举了如内存访问越界、空指针解引用等常见错误及其危害。同时,强调了动态内存管理中的注意事项,如内存泄漏和多次释放等问题,帮助读者理解和避免这些错误。

2万+





