为什么要动态内存空间分配
有时候我们需要的空间只有在程序运行的时候才知道,那么数组的固定开辟空间的方式不能满足需求。
动态内存分配函数
1.malloc函数和free函数
头文件:#include<stdlib.h> 使用格式:malloc(总字节数); malloc的返回值类型为:void* 所以malloc函数并不知道开辟空间的类型,具体类型要靠使用者进行强制类型转换 作用:向内存申请n个空间,申请成功后返回申请的空间的首元素的地址
int* p =(int*) malloc(11);
if (p == NULL)
printf("%s\n", strerror(errno));
else
{
for (int i = 0;i < 10;i++)
*(p + i) = i;
for (int i = 0;i < 10;i++)
printf("%-5d", *(p + i));
}
free(p);
p=NULL;
当申请的空间不再使用时,应该主动将申请的空间还给操作系统。 否则会一直占用空间到程序结束。如果在程序的结尾就没有太大的必要,因为在程序结束时会自动返还空间。 虽然指针p指向的空间被释放(既空间存储的参数清除),但指针p依然指向这份空间的地址,使用p依然可以找到这份空间。为了避免发生错误,在释放p的空间时要将p指向空指针。 malloc函数存在开辟失败的情况,所以malloc的返回值一定要检查。 free函数释放的空间必须是动态内存开辟的空间 free函数和malloc函数的头文件都是<stdlib.h> malloc函数与free函数要成对使用
2.calloc函数
头文件:#include<stdlib.h> 使用格式:calloc(元素个数,每个元素的大小); calloc的返回值类型为:void* 所以calloc函数并不知道开辟空间的类型,具体类型要靠使用者进行强制类型转换 作用:向内存申请n个空间并初始化为0,申请成功后返回申请的空间的首元素的地址 calloc函数与free函数要成对使用
3.realloc函数
头文件:#include<stdlib.h> 使用格式:realloc(要调整的内存地址,调整之后的空间大小); realloc的返回值类型为:void* 所以realloc函数并不知道开辟空间的类型,具体类型要靠使用者进行强制类型转换 作用:调整动态开辟内存空间的大小
int* p2 = (int*)realloc(p, 40);
if(p2!=NULL)
{
p=p2;
}
free(P);
p=NULL;
realloc函数作用机理图:
这时我们想要追加新的空间,有两种可能: 1.原先空间后面的空间足够,则在原先空间后面追加空间即可,那么返回原来空间的地址。
2.原先空间后面的空间不足,则新找一整块足够的空间重新开辟,并将原先空间中的数值复制过去, 复制后会自动释放原来的空间,那么返回新空间的地址。
realloc函数注意事项: 1如果p指向的空间之后有足够的内存空间,则字节追加,后返回p。 2如果p指向的空间之后没有足够的内存空间,则realloc函数和重新找一个新的内存区域来开辟一块满足需求的空间,并且将原来空间的数据拷贝回来,释放旧的内存空间,最后返回新开辟的内存空间的地址 3.倘若需要开辟的空间过大,realloc函数可能开辟失败,如果开辟失败,那函数将返回一个空指针。那么结果是不仅开辟失败,而且原来的开辟的地址丢失,无法查找,所以realloc函数的返回值一般不会直接放到原指针中。 realloc函数与free函数要成对使用
常见的动态内存分配错误
1.对NULL指针的解引用操作
int* p = (int*)malloc(40);
for (int i = 0;i < 10; i++)
*(p + i) = i;
free(p);
p = NULL;
避免方法:
在使用动态内存分配函数后一定要对返回值进行检查。
2.对动态开辟的内存的越界访问
int* p = (int*)malloc(20);
if (p == NULL)
return 0;
else
for (int i = 0;i < 10;i++)
*(p + i) = i;
free(p);
p = NULL;
避免方法:
养成在malloc函数填写参数时写(元素个数*每个元素的大小),明确总元素个数。
例如malloc(5*sizeof(int))
3.对非动态开辟内存使用free释放
int a = 10;
int* p = &a;
*p = 20;
free(p);
p = NULL;
常规开辟的内存存放在栈区
动态开辟的内存存放在堆区
free函数无法释放常规开辟的内存空间
4.使用free释放动态开辟内存的一部分
int* p = (int*)malloc(40);
if (p == NULL)
return 0;
else
for (int i = 0;i < 10;i++)
*p++ = i;
free(p);
p = NULL;
避免方法:
应在程序中避免让指针移动,找到代替代码。释放时注意指针所指向的位置
例如:在循环中(*p++)=*(p+i)
5.对同一块动态内存多次释放
int* p = (int*)malloc(40);
if (p == NULL)
return 0;
else
for (int i = 0;i < 10;i++)
*(p+ i) = i;
free(p);
free(p);
p = NULL;
避免方法:
1.团队中谁开辟谁释放。
2.一定要在free函数后面加p=NULL,这样即使后面再释放p也对程序无影响。
6.对动态开辟的内存忘记释放(内存泄漏)
while (1)
{
malloc(1);
}
如果不释放内存,那么对于这段空间自己不使用,而别人也无法使用,
则会白白占用大量内存,损耗性能。
避免方法:开辟使用后及时检查是否释放
|