动态内存管理

动态内存管理

    • 为什么存在动态内存分配
    • 动态内存函数
      • 1.malloc
      • 2.calloc
      • 3.realloc
      • 4.free

为什么存在动态内存分配

我们最熟悉内存开辟方式有:

 int val = 20;//在栈空间上开辟四个字节 
 char arr[10] = {
     0};//在栈空间上开辟10个字节的连续空间

但是上述的开辟空间的方式有两个特点:

  1. 空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
    但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态存开辟了。

动态内存函数

1.malloc

函数原型: void *malloc( size_t size );

头文件为:#include and #include
malloc函数的功能:是开辟size个字节大小的空间,并返回指向这块空间的指针。
如果开辟成功,则返回一个指向开辟好空间的指针。
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
如果参数 size为0,malloc的行为是标准是未定义的,取决于编译器。

假设我们要开辟n个整形空间:

/*malloc函数*/
#include
#include
#include
#include
int main()
{
     
	
	int n;
	scanf("%d", &n);
	//malloc向内存申请n个整形空间
	/*这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
	如果开辟成功,则返回一个指向开辟好空间的指针。
	如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。*/
	int* p = (int*)malloc(n*sizeof(int));
	
	if (NULL == p)
	{
     
		//打印错误信息
		printf("%s",strerror(errno));
	}
	else
	{
     
		//正常使用空间
		int i = 0;
		for (i = 0; i < n; i++)
		{
     
			*(p + i) = i;
			printf("%d ", *(p + i));
		}
	}
	//当动态申请的空间不再使用时
	//还给操作系统
	/*free函数用来释放动态开辟的内存。
	如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
	如果参数 ptr 是NULL指针,则函数什么事都不做*/
	free(p);	//后面介绍
	p = NULL;
	return 0;
}

注意:malloc开辟的内存空间,不会对这开辟的空间进行任何的初始化,这块开辟的内存空间里面存储的值是随机值。

2.calloc

C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配。

函数原型:void *calloc( size_t num, size_t size );

头文件为:#include and #include
函数功能:与malloc相似,函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。唯一的不同点为就是calloc函数会把这开辟的空间的值初始化为0。

举个例子:

/*calloc函数*/
#include
#include
#include
#include
int main()
{
     

	int n;
	scanf("%d", &n);
	//calloc向内存申请n个整形空间
	int* p = (int*)calloc(n,sizeof(int));
	
	if (NULL == p)
	{
     
		//打印错误信息
		printf("%s",strerror(errno));
	}
	else
	{
     
		//正常使用空间
		int i = 0;
		for (i = 0; i < n; i++)
		{
     
			//calloc把申请内存的值全部初始化为0
			printf("%d ", *(p + i));
		}
	}
	//释放空间
	free(p);	//后面介绍
	p = NULL;
	return 0;
}

3.realloc

有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。

函数原型:void *realloc( void *memblock, size_t size );

头文件为:#include and #include
函数功能:memblock是要调整的内存地址size调整之后新大小,返回值为调整之后的内存起始位置。这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

realloc在调整内存空间的是存在两种情况:
情况1:原有空间之后有足够大的空间。
情况2:原有空间之后没有足够大的空间。
动态内存管理_第1张图片

举个例子:

/*realloc函数*/
#include
#include
#include
#include
int main()
{
     
	int* p = (int*)malloc(20);
	if (NULL == p)
	{
     
		printf("%s\n", strerror(errno));
	}
	else
	{
     
		int i = 0;
		for (i = 0; i < 5; i++)
		{
     
			*(p + i)=i;
		}
	}
	//就是在使用malloc开辟的20个字符空间
	//假设这里,20个字节不能满足我们的需求了,希望我们能够有40个字节的空间,这里我们就可以使用remalloc来调整动态开辟的内存
	//函数原型----void *realloc( void *memblock, size_t size );
	//void *memblock-----需要调整的内存地址   size_t size-----调整之后新的大小
	//返回值为调整之后的内存起始位置	


	//realloc使用的注意事项
	//1.如果p指向的空间之后有足够的内存空间可以追加,则直接追加,后返回p
	//2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重现找一个新的内存区域
	//开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟的内存空间地址
	//3.得用一个新的变量来接收realloc函数的返回值,不然万一失败,会把原来空间的值丢失掉

	int* ptr =(int *)realloc(p, 40);
	//防止开辟失败,使得原来的p找不到了
	if (NULL != ptr)
	{
     
		p = ptr;

		//使用扩展的内存块
		int i = 0;
		for (int i = 5; i < 10; i++)
		{
     
			*(p + i) = i;
		}

		for (i = 0; i < 10; i++)
		{
     
			printf("%d ", *(p + i));
		}
	}

	//释放内存
	free(p);
	p = NULL;
	return 0;
}

4.free

函数原型:void free( void *memblock );

头文件:#include and #include
函数功能:用来释放动态开辟的内存。
如果参数memblock指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数memblock 是NULL指针,则函数什么事都不做。

你可能感兴趣的:(c语言)