1.动态内存函数
malloc
向内存申请一块连续的可用空间,并返回指向这块空间的指针
malloc实现内存分配,当程序调用malloc时,malloc会从内存中取出一块合适且地址连续的内存(没有初始化),并把内存的首地址返回。但是malloc不知道我们申请的类型,所以特的返回值必须是void,可以转换成任意类型的指针。我们接受返回值时必须要进行强制类型转换。如果内存不足,则会返回一个空指针(NULL)。所以malloc开辟的空间在使用时我们必须检查返回值是否为空。其中size为所申请的个数。*
void *malloc (size_t size);
int *a=(int* )malloc(100*sizeof(int))
申请100个整形内存
calloc
calloc与malloc的区别
calloc也能实现动态内存的分配,不同点是:
- 使用calloc申请的空间会被初始化为0(在返回首地址之前)
- calloc需要两个参数,一个是元素的个数,一个是每个元素所占的字节数。
void *calloc(size_t n,size_t size)
int *b=(int *)calloc(100 ,sizeof(int));
relloc(修改内存的大小,只可以扩大. 缩小)
relloc用于修改一个已经分配好内存内存块大小,使用recallo函数可以是原内存扩大或缩小。
void *relloc(void *ptr,size_t,nwesize);
其中ptr指原内存的地址,nwesize是指连同旧内存一起,所需的总内存大小
- 扩大内存:那么他会保存原内存的内容,并在原内存的后面开辟要增加的字节的空间。而不是对新增加的内存进行初始化。如果原内存块后面的空间小于新增加字节的大小,则realloc会在内存中重新找一块满足空间的要求。把原内存的内容复制过去,并返回新的地址。使用reallo后就不能使用旧内存的地址了,应该使用新内存的地址。
- 缩小内存:realloc 会将原内存的尾部的部分释放。
int i;
int *b=(int *)calloc(100,sizeof(int));
for(i=0;i<100;i++)
{
b[i]=i;
}
int *a=(int*)malloc(200*sizeof(int));
for(i=0;i<200;i++)
{
a[i]=b[i];
}
free(b);
b=a;
b=NULL;
free(释放内存)
free(p);
free函数的返回值必须为NULL,或者是malloc,relloc, calloc 的返回值
释放内存(用完内存后必须释放,不然会发生内存泄漏,内存越用越少)。当释放完空间后指针p仍然指向内存起始的位置,所以还要手动的将地址p赋值为空,即p=NULL.
使用free时一定要确保不在访问被释放内存的地址
动态内存常见使用错误
1.没有检查内存是否分配成功
2.内存越界
3.使用free释放内存后,仍然访问被释放内存的地址
4.free崩溃的原因
对动态开辟内存的越界访问
int main()
{
int *p =(int *) malloc(10*sizeof(int)); //10个整型
int i = 0;
for(i=0; i<20; i++) //20个整型
{
*(p+i) = i;
}
free(p);
return 0;
}
int main()
{
int *p =(int *) malloc(10*sizeof(int)); //10个整型
int i = 0;
int a = 10;
for(i=0; i<20; i++) //20个整型
{
*(p+i) = i;
}
p = &a; //
free(p);
return 0;
}
问题一: p在这里并不是存的动态内存开辟的地址,那下面free的p也不是动态内存开辟的空间,而是a,我们发现a并不是动态内存开辟的,所以这里就出现了
对非动态开辟内存使用free释放。
问题二: 我们正儿八经动态开辟的空间却没有得到释放,所以就内存泄漏了。(动态内存开辟出来之后,不用,也不还,找不到,释放不了就是内存泄漏。)
重复释放同一块内存
int main()
{
int *p1=(int *)malloc(10*sizeof(int));
int *p2(int *)malloc(20*sizeof(int));
p1=p2;
//p2=NULL;
free(p1);
//free(p2);//此处p1,p2同指一段内存
}
释放的不是动态开辟的内存
void()
{
int a=10;
int *p=&a;
free(p); //p不是动态开辟的空间
}
动态开辟的空间忘记释放(内存泄露)
void test()
{
int *p = (int *)malloc(sizeof(100));
if (NULL != p)
{
*p = 20;
}
}
int main()
{
test();
return 0;
}
柔性数组
结构体中的最后一个元素允许是未知大小的数组,这就叫做柔型数组。
柔性数组有什么用途 ?它的主要用途是为了满足需要变长度的结构体,为了解决使用数组时内存的冗余和数组的越界问题。
柔型数组的特点:
1、结构中的柔性数组成员前面必须至少一个其他成员。/1、sizeof 返回的2、这种结构大小不包括柔性数组的内存。
3、包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
struct test
{
int a;
double b;
char c[];
};
c同样不占用test的空间,只作为一个符号地址存在,而且必须是结构体的最后一个成员。柔性数组成员不仅可以用于字符数组,还可以是元素为其它类型的数组