目录
在没学习动态内存开辟的时候,我们最常用的开辟内存方法应该是如下吧。
int arr1[20];
char arr2[20];
但是以上方法有一些缺点,比如说:
1.它的大小是固定的,不能随着需求的变化而变化
2.它需要在程序运行起来的时候才知道内存空间是浪费了还是缺少了。
所以就引进了动态内存管理的概念。
动态内存函数的介绍
在c语言中为我们提供了两个函数 malloc和free
malloc
void* malloc(size_t size)
这个函数会向内存的堆区中申请一块连续的内存,并且返回这块空间的地址
1.函数开辟成功会返回开辟的地址。
2.函数开辟失败,会返回NULL.
3.函数的返回值类型是void*需要根据需求进行转换。
4.如果size=0,是否有意义取决于编译器。
free
void free(void *ptr)
free函数会回收被动态内存开辟的空间。
如果ptr不是动态开辟的那么free的执行结果取决于编译器。
如果给ptr传入NULL那么free会什么也不做。
举个例子
int main()
{
int n=0;
scanf("%d",&n);
char *ptr=(char *)malloc(n*sizeof(int));
if(ptr==NULL)
{
perror(malloc);
}
else
{
int i=0;
for(i = 0 ; i < n; i++)
{
ptr[i]=i;
printf("%d",ptr[i]+1);
}
}
free(ptr);
ptr=NULL;
return 0;
}
calloc
void *calloc(size_t num,size_t size)
他也是一个动态内存开辟函数,它的作用和malloc有一些不同,它会将开辟的空间默认制成‘0’,
开辟num个size大小的空间。
realloc
realloc函数的出现让动态内存开辟有了灵魂,它会更加的灵活,realloc会在原来malloc或calloc函数开辟的那块空间上进行空间大小的增改。
Void * realloc(void *ptr,size_t num)
ptr是需要调整空间的地址,num是它新的大小,返回值为调整后的内存地址,realloc函数在调整的时候还会原来内存中的数据移动到新的内存里
在调用realloc函数的时候会出现两种情况,
1.再增加内存的时候内存原有空间足够大。
2.原空间没u的那么大的内存。
当发生第一种情况的时候,realloc会正常的开辟空间返回该控件的地址,当发生第二种情况的时候realloc函数会在堆区中寻找一块连续的足够大的内存,并且把原来存放的内容全部搬运到新的内存空间中,并且返回新的地址。
柔性数组
struct s3
{
int num;
int arr[];
};
像arr这样,在结构体中的最后一个成员是未指定大小的数组就叫做柔性数组。
柔性数组的特点
1.柔性数组必须是一个结构体的最后一个成员.
2.结构体大小和柔性数组无关。
3.通过malloc,realloc等函数进行灵活使用,但是开辟的空间大小要大于结构体大小来满足柔性数组的空间使用。
柔性数组的使用:
struct s3
{
int num;
int arr[];
};
int main()
{
struct s3* ptr=(struct s3*)malloc(sizeof(struct s3)+100*4);
ptr->num = 100;
for(int i=0; i < 100; i++)
{
ptr->arr[i] = i + 1;
}
free(ptr);
ptr = NULL;
return 0;
}
柔性数组的优势:
1.方便释放内存,像完成上面的那个代码如果不用柔性数组的话就要这么写
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct s4
{
int num;
int* pc;
};
int main()
{
struct s4* ptr1 = (struct s4*)malloc(sizeof(struct s4));
ptr1->pc = (struct s4*)malloc(sizeof(int) * 100);
int i = 0;
for (i = 0; i < 100; i++)
{
ptr1->pc[i] = i + 1;
printf("%d ", ptr1->pc[i]);
}
free(ptr1->pc);
ptr1 = NULL;
free(ptr1);
ptr1 = NULL;
return 0;
}
和之前的那个对比来看,这种写法会两次开辟空间,导致存放的数据空间不是连续的,内存访问速度会下降,再就是释放开辟的空间的时候要释放两次,并且应该分先后顺序。使用起来很麻烦,不是很方便,如果我们在函数中使用上面这种代码,那么然后用户调用free他们不会知道要结构体中的内容也要free。
这是本人学习记录的博客如果有错误欢迎提醒,谢谢你,耐心地看完。