C语言:《动态内存函数》《malloc》《calloc》《relloc》《动态内存常见错误》

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也能实现动态内存的分配,不同点是:

  1. 使用calloc申请的空间会被初始化为0(在返回首地址之前)
  2. 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是指连同旧内存一起,所需的总内存大小

  1. 扩大内存:那么他会保存原内存的内容,并在原内存的后面开辟要增加的字节的空间。而不是对新增加的内存进行初始化。如果原内存块后面的空间小于新增加字节的大小,则realloc会在内存中重新找一块满足空间的要求。把原内存的内容复制过去,并返回新的地址。使用reallo后就不能使用旧内存的地址了,应该使用新内存的地址。
  2. 缩小内存: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的空间,只作为一个符号地址存在,而且必须是结构体的最后一个成员。柔性数组成员不仅可以用于字符数组,还可以是元素为其它类型的数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值