动态内存浅析

首先,我们先来谈谈为什么要使用动态内存分配?


      我们都知道,数组是相同元素的一组集合,它的各个元素之间也是连续存储的,所以内存会在编译阶段就为其分配所需的空间,而且在定义数组时就需要准确的标明数组的元素个数,这就导致了数组的长度不得不在运行时候方可得知,因为数组元素所占空间必须由输入数据来决定,这点就形成了数组本身致命的缺陷,同时也影响了程序的灵活性与健壮性。

       定义数组时,元素个数写大了,实际没那么多元素,浪费空间,而元素个数写小了又不够用,还可能导致越界访问,但是程序本身并没有为此做出一种合理的响应,所以必然会导致错误。你可能会说,可以按需要输入的数据个数定义数组啊,可是程序是灵活多变的,大多数情况下,我们都是事先不可预知的。

      为了解决此问题,我们引入了动态内存分配的概念,专门用来解决运行时才知道所需空间的数组的内存分配。


接下来我们介绍一下动态内存分配过程中最常见到的4个函数,他们分别是:malloc,calloc,realloc,free.


1.malloc:分配内存的函数之一,当程序调用malloc动态开辟内存时,malloc会从内存池中开辟一块连续的内存,并且返回所开辟内存的首地址。如果内存池为空,或者说可用内存无法满足你的请求,malloc函数会向操作系统发出请求,要求得到更多的内存,并在这块新内存上执行分配任务。如果操作系统都无法提供更多的内存,则malloc函数会返回一个NULL指针。所以,动态内存是否开辟成功的判空是非常必要的

       其次需要注意的是,malloc函数开辟内存的同时,并没有以任何方式对其初始化,这就不得不要求我们手动对开辟的内存进行初始化

       最后,当一块已经开辟好的内存不再使用时,必须结合free函数将其归还给内存池以便以后只需,毕竟好借好还再借不难嘛,嘻嘻。


malloc函数和free函数的原型如下:

void  *malloc(size_t size);//参数size为需要分配内存的字节数,              

                                      返回值void *可接收任何类型的指针,使用时必须强制类型转换

void  free(void  *pointer);//参数可为malloc函数的返回值


下面看一个malloc函数动态申请内存的例子:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int *parr = (int *)malloc(10*sizeof(int));//强制类型转换勿忘
	if(NULL == parr)//判空
	{
	    printf("out of memory\n");
		exit(1);//异常结束程序
	}
	else
	{
	    int i = 0;
		for(i=0; i<10; i++)
		{
			*(parr+i)=i*2;
			printf("%d ",*(parr+i));
		}
	}
	free(parr);//释放空间
	parr = NULL;//释放之后最好置空
    system("pause");
}
程序运行结果:



2.realloc:用来修改原先已经分配好的内存块的大小。如果是扩大一个内存块,则realloc函数会将原先的内容依然保留,新增加的内存增加到原有内存块的后面,并返回其首地址。一旦后面的内存不够扩充,则拷贝原有内容在内存池中寻找一块更大的内存块,并且自动释放原来的内存空间,此时返回新内存块的首地址

      如果realloc用于缩小一块内存,该内存块尾部的部分便被拿掉,剩余部分内存的内容依然保留。

函数原型:void  *realloc(void  *ptr,size_t  new_size);


使用范例:

<pre name="code" class="cpp">#include<stdio.h>
#include<stdlib.h>
int main()
{
	int *parr = (int *)malloc(10*sizeof(int));//强制类型转换勿忘
	if(NULL == parr)//判空
	{
	    printf("out of memory\n");
		exit(1);//异常结束程序
	}
	else
	{
	    int i = 0;
		int *new_parr = NULL;
		for(i=0; i<10; i++)
		{
			*(parr+i)=i*2;
		}
		new_parr = (int *)realloc(parr,15*sizeof(int));//扩大原有内存
		if(NULL == new_parr)//判空
		{
			printf("out of memory\n");
			exit(1);//异常结束程序
		}
		else
		{
		    parr = new_parr;
		}
		for(i=10; i<15; i++)
		{
			*(parr+i)=i*2;
		}
		for(i=0; i<15; i++)
		{
			printf("%d ",*(parr+i));
		}
		free(parr);//释放空间
	    parr = NULL;//释放之后最好置空
	}
    system("pause");
	return 0;
}


 结果: 

<pre name="code" class="cpp">#include<stdio.h>
#include<stdlib.h>
int main()
{
	int *parr = (int *)malloc(10*sizeof(int));//强制类型转换勿忘
	if(NULL == parr)//判空
	{
	    printf("out of memory\n");
		exit(1);//异常结束程序
	}
	else
	{
	    int i = 0;
		int *new_parr = NULL;
		for(i=0; i<10; i++)
		{
			*(parr+i)=i*2;
		}
		new_parr = (int *)realloc(parr,5*sizeof(int));//缩小原有内存
		if(NULL == new_parr)//判空
		{
			printf("out of memory\n");
			exit(1);//异常结束程序
		}
		else
		{
			parr = new_parr;
		    for(i=0; i<5; i++)
			{
				printf("%d ",*(parr+i));
			}
			free(parr);//释放空间
			parr = NULL;//释放之后最好置空
		}
	}
    system("pause");
	return 0;
}


 
 
注意:realloc只能用于修改动态开辟的内存 

3.calloc:用于内存分配,其优点是开辟内存的同时将其初始化为0,但是你的程序如果仅仅是想把一些值存储到数组中,则此初始化纯属浪费空间,所以是好处还是坏处,由你自己决定。

函数原型:void *calloc(size_t num_elements,size_t element_size);

应用举例:

#include <stdio.h>
#include <stdlib.h>

int main ()
{
  int i,n;
  int * pData;
  printf ("Amount of numbers to be entered: ");
  scanf ("%d",&i);
  pData = (int*) calloc (i,sizeof(int));
  if (pData==NULL) exit (1);
  for (n=0;n<i;n++)
  {
    printf ("Enter number #%d: ",n);
    scanf ("%d",&pData[n]);
  }
  printf ("You have entered: ");
  for (n=0;n<i;n++) printf ("%d ",pData[n]);
  free (pData);
  return 0;
}
s

4.free:释放动态开辟一个的内存,它的参数要么是NULL,要么是先前从malloc,calloc或realloc返回的值。向free传递一个NULL参数不会产生任何效果。

原型:void  free(void  *pointer);


5.malloc,calloc和realloc之间的区别与联系:

void  *malloc(size_t size);//参数为开辟内存的字节数

void  *realloc(void  *ptr,size_t  new_size);//参数1是malloc或calloc发返回值,参数二为                                                                    需要修改内存的新字节数

void *calloc(size_t num_elements,size_t element_size);//参数1是元素的个数,参数2位                                                                                       每个元素所占的字节数


(1)参数不同,malloc只有一个参数,而calloc和realloc都有两个参数,如上。

(2)malloc申请空间不会对其初始化,而calloc会主动初始化(0)。

(3)malloc或calloc用于动态申请内存,而realloc专门用于修改malloc或calloc动态申请的      内存。

(4)如果realloc函数的第一个参数是NULL,则它的行为就和malloc一模一样。

(5)三者都需要进行判空和释放。如果使用完成并不释放,则可能导致内存泄漏。就算释      放完成但返回值依旧指向初始位置,所以置NULL也是必不可少的操作。


6.动态内存开辟的常见错误

(1)忘记判NULL,释放,和置NULL。

(2)操作内存越界访问。

(3)释放内存后依旧访问被释放内存的地址,记得一定确保使用完成再释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值