您现在的位置是:首页 > 正文

面试官:如何使用malloc、free、calloc、realloc动态内存开辟函数

2024-04-01 02:30:24阅读 7

目录

1 malloc和free

2 calloc

3 realloc


1 mallocfree

C语言提供了一个动态内存开辟的函数:

 参数表示我要开辟多少个字节。

这个函数向内存申请一块连续可用的空间, 并返回指向这块空间的指针。

  1. 如果开辟成功,则返回一个指向开辟好空间的指针。
  2. 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  3. 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
  4. 如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。

C语言提供了另外一个函数 free ,专门是用来做动态内存的释放和回收的。

 free用来释放动态开辟的内存。

  1. 如果参数 memblock 指向的空间不是动态开辟的,那 free 函数的行为是未定义的。
  2. 如果 memblock 是NULL指针,则函数什么时都不做。

 先来看 malloc 如何使用

开辟成功的例子:

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

int main()
{
	int arr[10] = { 0 };
    //开辟40个字节的空间
	int* p = (int*)malloc(40);//malloc返回类型为void*,所以要强制类型转换成int*
    //判断开辟空间是否成功
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//开辟成功,开始使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;//找到数组元素并赋值
	}
	//打印数组元素
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;;
}

代码结果:

开辟失败的例子:

这里会使用 INT_MAX它的意思是整形的最大值。鼠标右击点过去,出现以下弹窗后再点击转到定义。

 点击转到定义后会出现以下界面。

 代码展示:

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

int main()
{
	int arr[10] = { 0 };
	int* p = (int*)malloc(INT_MAX);//整形最大值
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//开辟成功,开始使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;//找到数组元素并赋值
	}
	//打印数组元素
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;;
}

代码结果:空间开辟失败

整形数组和 malloc 开辟出来的空间有什么不一样的吗

 整形数组在栈区开辟空间,malloc 在堆区开辟空间。

内存泄露:

在使用完一块空间后,没有把它还回去,自己也不再继续使用,导致别人也没有办法使用,这就叫内存泄露,好像是这块空间消失了一样。比如说,我借给你一本书,你又不看,又不还给我,导致我也看不了,这本书就没意义了。

注意没有 free 并不是说内存空间就不会回收了,当程序退出的时候,系统会自动回收内存空间的。

free 如何使用

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

int main()
{
	int arr[10] = { 0 };
	//开辟40个字节的空间
	int* p = (int*)malloc(40);//malloc返回类型为void*,所以要强制类型转换成int*
	//判断开辟空间是否成功
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//开辟成功,开始使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;//找到数组元素并赋值
	}
	//打印数组元素
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	//释放内存
	free(p);
	p = NULL;
	return 0;;
}

 free 的意思是把刚刚开辟的40个字节的空间还给操作系统了,执行 free 释放内存后,可以看到 p 的值没有改变,所以最合适的方法是将 p 设为空指针(NULL)。

p 虽然将空间还回去了,但是依然可以用地址访问到之前的空间。如果真要访问的话,会造成野指针,将会是一件十分危险的事情。所以为了防止野指针的出现,将它置为空指针。

看到这里可以发现,malloc 和 free 是一对的,在写代码的时候这两个要搭配使用。做到 malloc 开辟,free 释放。

2 calloc

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

  1.  函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。
  2. 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为0

例子:

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

int main()
{
	//开辟10个整形的空间
	int* p = (int*)calloc(10, sizeof(int));
	//判断是否开辟成功
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//开辟成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	//释放
	free(p);
    p = NULL;
	return 0;
}

代码结果:

可以看到数组内容被初始化成了全0.

3 realloc

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

  1. memblock是要调整的内存地址
  2. size调整之后新大小
  3. 返回值为调整之后的内存起始位置。
  4. 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
  5. realloc在调整内存空间的是存在两种情况:

本身有40个字节,要增加40个字节,总共是80个字节。(调整之后的大小)


情况1:原有空间之后没有足够大的空间

 如果是情况1的时候该怎么做呢?

  1. realloc 会直接开辟80个字节的空间来使用,而之前开辟的会覆盖使用过空间的空间则不会使用。
  2. 它会先找到旧的空间,把旧的空间里的数据拷贝过来。
  3. 返回的时候会返回新的空间的起始地址,给我们的感觉就好像是空间增加了40个字节。
  4. 而旧的空间不需要手动释放,旧的空间会被 realloc 自动释放。

示意图


情况2:原有空间之后有足够大的空间

 在旧的空间后面直接增加40个字节的空间,与情况1不同的是,情况2返回的是旧的地址。

 ptr 和 p 的地址一样,说明这是属于第2种空间足够的情况,返回的是旧地址。

 先将要开辟的空间设置的大一点,这样比较好观察第1中情况。

 两个地址不一样,说明这是属于第2中空间不够用的情况,返回的是一个新地址。

代码演示

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

int main()
{
	int* p = (int*)malloc(40);
    //判断
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//开辟成功,使用 - 初始化为1~10
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;
	}
	//扩容
	int* ptr = (int*)realloc(p, 80);
	//判断ptr是否有效
	if (NULL != ptr)
	{
		p = ptr;
	}
	//使用
	for (i = 0; i < 10; i++)
	{
		printf("%d ", * (p + i));
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

代码结果:

网站文章