欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【C语言】动态内存分配(malloc,realloc,calloc,free)的基本理解和区别

程序员文章站 2022-03-09 15:17:37
...

一.为什么要使用动态内存分配???

     以一个数组为例:在定义一个数组时给定了其内存空间,只要给定足够大的空间,就可以放入你所需的数据元素。但当内存空间小于所需放入的元素个数时,我们就需要给这个内存空间去增容,以此来满足你的需求。

      上述定义数组时设置足够大的内存空间看似简单,但却有以下缺点:

            1.如果内存空间很大,数据却很少就会使内存空间浪费。

            2.如果内存空间不足就会出现溢出的现象。

二.malloc

  1.   函数原型:

//头文件
#include<malloc.h>

//函数原型
void *malloc(sizt_t size);

malloc的参数就是需要所分配的字节数。

2. malloc在C语言中不是关键字而是C函数库中提供的函数。如果需要进行内存分配时在调用malloc时就是在内存池中提取一块内存空间(在堆上申请一块空间),但是这块空间是连续的空间。,并向该程序返回一个这块内存的指针。

注意:在申请完空间后需要自己去初始化这块空间,如果懒得动手那就可以用realloc(下面会介绍)

3.malloc进行内存分配的特点:

    (1.)所申请的空间是连续的

    (2.)在有的编译器下申请的空间略大于你请求申请的内存空间

    (3.)malloc所返回的内存起始位置将始终能够满足对边界对齐

4.malloc是如何知道你所申请的内存空间是什么类型?

     这是因为在使用malloc进行内存分配时会返回void*类型的指针,但是这个指针可以转化为任意类型的指针。(但是有些老式的编译器需要你去强转你所需要的类型)

#include<Windows.h>
#include<stdio.h>
#include<malloc.h>

int main()
{
	int* p = NULL;
	printf("%x\n", p);
	p = (int*)malloc(sizeof(int)* 25);
	if (NULL == p)
	{

		printf("申请失败!!!");
		return 0;

	}
	printf("%x\n", p);
	system("pause");
	return 0;
}


注意:由上边代码可以看到当用malloc动态分配空间后一定要进行对申请的空间进行判断是否申请失败,这点很重要。

二.calloc

    函数原型:

//有文件
#include<stdlib.h>

//源文件
void* calloc(size_t num_elements,size_t element_size);

calloc和calloc的动态分配内存是有相同之处,他们的主要区别在于:

(1.)在函数原型中calloc多了一个参数(他的参数是由所需元素的个数和每个元素的字节数组成)

(2.)最大区别:calloc在调用完后返回指向内存的指针之前把他初始化为0

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

int main()
{
	int* p = NULL;
	int* p1 = NULL;

	p = (int*)malloc(sizeof(int)* 5);
	if (NULL == p)
	{

		printf("申请失败!!!");
		return 0;

	}
  
	printf("malloc:\n");

	for (int i = 0; i < 5; i++)
	{
		printf(" %d-->", *p);
		*p++;

	}
	printf("\n");

	p1 = (int*)calloc(5, sizeof(int));
	if (NULL == p1)
	{

		printf("申请失败!!!");
		return 0;

	}

	printf("calloc:\n");
	for (int j = 0; j < 5; j++)
	{

		printf(" %d-->",*p1);
		*p1++;

	}
	
	system("pause");
	return 0;
}

【C语言】动态内存分配(malloc,realloc,calloc,free)的基本理解和区别

注意:在调用完calloc后也要进行判断是否申请成功

三.realloc

  函数原型:

//头文件
#include<stdlib.h>

//原型
void realloc(void *ptr, size_t new_size);

ptr是指向原来地址的指针。

这个函数用于修改一个原先已经分配内存块的大小。

使用:

1.可以使一块内存扩大或缩小(原来的内存块可以扩大缩小)

  (1.)如果是扩大一个内存块,则将原来的内存块保留在他的后边新增一块内存块(但是新增的内存块并未初始化)

  (2.)如果是缩小一块内存块,则将该内存块的后半部分直接拿掉,剩余部分内存块及其内容保留。

2.原来的内存块无法扩大缩小

   如果是着这种情况,realloc会重新开辟一个新的内存空间,并把原来的内存空间的内容拷贝到新的内存空间里。

注意:再调用完realloc后就不能使用指向就内存的指针,而是用返回的新的指针。

【C语言】动态内存分配(malloc,realloc,calloc,free)的基本理解和区别

值得一提的是:如果realloc中的第一个参数如果为空则和malloc一样。

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

int main()
{
	const int size = 2000;
	int *p = (int *)malloc(20 * sizeof(int));
	int *p1 = (int *)realloc(p, size*sizeof(int));
	
	printf("%x\n", p);
	printf("%x\n", p1);
	system("pause");
	return 0;
}




【C语言】动态内存分配(malloc,realloc,calloc,free)的基本理解和区别

四.free(释放空间)

函数原型:

free(void* pointer);

free的参数必须要不时空,要不然就必须是malloc,calloc,realloc中返回值。

注意:在使用malloc,calloc,realloc进行内存分配后一定要进行释放空间。

五.内存空间

【C语言】动态内存分配(malloc,realloc,calloc,free)的基本理解和区别

以上的操作都是在堆上进行