动态内存及有关动态内存的函数

 

前言:为什么要使用动态内存???

       通常在我们声明一个数组时必须要指定数组的长度,但数组的长度只有程序运行的时候知道,而且数组的所需的内存空间取决于输入数据的类型。这种方法虽然很简单,但它的缺点是显而易见的。他极大的限制了程序的灵活性和健壮性。一旦我们输入的元素超过了数组的长度时(越界),程序就很容易崩溃。如果数组很大,我们输入的数据的元素很少,这样就浪费了内存空间。最重要的是,如果我们的输入长度超过了数组长度,编译器是不会报错的,他会把数组存满,剩下的元素不在存取。这样使得程序输出一个错误的值。所以我们有的时候需要使用动态内存。

     动态内存是为了解决那些在运行时才知道所需要的内存空间的数组的内存分配。

首先我们了解malloc,calloc,realloc,free这四个函数。

1.malloc

   malloc实现内存分配,当程序调用malloc时,malloc会从内存中取出一块合适且地址连续的内存(没有初始化),并把内存的首地址返回。但是malloc不知道我们申请的类型,所以特的返回值必须是void*,可以转换成任意类型的指针。我们接受返回值时必须要进行强制类型转换。如果内存不足,则会返回一个空指针(NULL)。所以malloc开辟的空间在使用时我们必须检查返回值是否为空。其中size为所申请的个数。

void *malloc(size_t,size)

eg:这个表示申请一百个整型内存

int *a=(int*)malloc(100*sizeof(int));

2.calloc 

    calloc 也能实现动态内存的分配。但它与malloc有两个不同的区别:

       (1)使用calloc申请的空间会被初始化为0(在返回首地址之前)

       (2)calloc需要两个参数,一个是元素的个数,一个是每个元素所占的字节数。

void *calloc(size_t n,size_t size)

eg:

​
int *b=(int *)calloc(100,sizeof(int));

​int *a=(int*)malloc(100*sizeof(int));//该代码段等同于int *b=(int *)calloc(100,sizeof(int));
for(int i=0;i<100;i++)
{
	a[i]=0;
}

然而calloc与memsert函数有相同的功能。只是memsert多了一个参数。但他们都仅限与置零。

memsert(arr,0,100*sizeof(int))

3.realloc(修改内存的大小,只可以扩大,缩小)

relloc用于修改一个已经分配好内存内存块大小,使用recallocha函数可以是原内存扩大或缩小。

void *realloc(void *ptr,size_t,nwesize)

 其中ptr指原内存的地址,neisize是指连同旧内存一起,所需的总内存大小

(1)扩大内存:那么他会保存原内存的内容,并在yuan'n原内存的后面开辟要增加的字节的空间。而不是对新增加的内存进行初始化。如果原内存块后面的空间小于新增加字节的大小,则realloc会在内存中重新找一块满足空间的要求。把原内存的内容复制过去,并返回新的地址。使用reallo后就不能使用旧内存的地址了,应该使用新内存的地址。

(2)缩小内存:realloc 会将原内存的尾部的部分释放。

eg:

将原来的100个整型类型扩大到200个整型类型。

void Mubble()
{
	
	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;
}

4.free(释放内存)

free(p);

(1)free的参数必须为NULL,或者是realloc,malloc,calloc的返回值。不用传内存长度。

(2)释放内存(用完内存后必须释放,不然会发生内存泄漏,内存越用越少)。当释放完空间后指针p仍然指向内存起始的位置,所以还要手动的将地址p赋值为空,即p=NULL.

 使用free时一定要确保不在访问被释放内存的地址

2.动态内存使用常见的错误

1.没有检查内存是否分配成功

2.内存越界

3.使用free释放内存后,仍然访问被释放内存的地址

4.free崩溃的原因

<1>越界(修改了尾信息

int main()
{
int arr=(int *)malloc(10*sizeof(int));
for(int i=0;i<10;i++)
{
a[i]=0;
}
free(arr);//此处i越界导致free崩溃

系统分配给程序的内存就好像切蛋糕一样将内存分配给他们,当free回收内存就像把原来的蛋糕拼接回去。

头和尾记录了内存的大小,当数组越界时就会改掉尾信息。

<2>指针指向发生了改变(修改了头信息

int main()
{
int *p=(int *)malloc(10*sizeof(int));
for(int i=0;i<10;i++)
{
p[i]=0;
/*p=0;
p++;
p++=0;这两种置零方式都会让指针的指向发生了改变
*/
}
free(arr);
}

<3>重复释放同一段内存

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同指一段内存
}

<4>释放不是动态开辟的内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值