C语言中动态内存分配malloc、calloc和realloc函数解析

 更新时间:2022年03月10日 11:15:20   作者:寄一片海给你  
C语言跟内存申请相关的函数主要有 alloca、calloc、malloc、free、realloc等,下面这篇文章主要给大家介绍了关于C语言中动态内存分配malloc、calloc和realloc函数的相关资料,需要的朋友可以参考下

前言

有时候我们需要的空间大小不确定,需要随着程序需要的空间而变化, 那以数组开辟的固定大小的空间就不适用了, 这时候我们就需要动态分配开辟空间了。当空间不够时就扩容。动态开辟是在堆区开辟一块连续可用空间,并返回这块空间的地址。有三种函数malloc, calloc和realloc。我们动态内存分配就在堆区开辟空间

上面的四个区只有堆区的空间是需要手动释放的

free函数

free函数是专门用来对动态开辟内存的回收和释放的。当我们不需要再使用动态开辟的空间时,一定要free释放空间,因为是在堆上开辟的空间,所以不会随着出了作用域而销毁,需要我们free释放,避免内存泄漏,并置空(将指针置为NULL),避免形成野指针。

内存释放是标记删除, 只会修改当前空间的所属状态,并不会清除空间内容。

当然内存泄漏也不是都有危害,但为了养成良好的代码习惯,动态开辟后一定要free

void free (void* ptr);

1.如果参数ptr指向的内存空间不是动态内存开辟的,那free函数的行为是未定义的,就会报错,所以free函数是针对动态开辟的空间

2.如果ptr是 NULL空指针,那么free函数什么都不做。

下面我们来实现一下。

动态内存分配需要调用头文件#include<stdlib.h>

malloc函数

void* malloc (size_t size);

malloc函数用来动态开辟的, size是开辟所需空间的大小,单位:字节。

并返回起始地址。返回类型是void*,表示我们可以开辟任意类型的空间,同时我们需要强制类型转换成我们开辟空间类型的指针,再用指针接收

例如我们开辟的是int型的空间,就需要先转换为(int*),再用int*的指针接收

开辟float型的空间,就需要先转换为(float*),用于float*的指针接收

int* p = (int*)malloc(sizeof(int) * 10);

重点:

1.malloc函数在开辟空间后需要判断开辟空间是否成功,若开辟成功会返回开辟好的空间的指针,开辟失败会返回空指针。

2.malloc函数并不会对开辟空间进行初始化,空间内容为随机数。

下面是关于malloc函数的例子,主函数如下:

主函数中第一段代码就是在堆上动态开辟10个int型大小的空间,通过int*型的指针p去维护这块空间,如果空间开辟失败就会返回NULL,所以我们需要判断是否开辟成功。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{	
	int* p = (int*)malloc(sizeof(int) * 10);
	if (p == NULL)
	{                                     //我们也可以直接eixt(-1)异常退出,或是return;
		printf("%s\n", strerror(errno));  //strerror(errno)是用来判断开辟失败的错误原因                               
		return -1;                        //error是错误码
	}                                     //需要调用最下面的两个头文件
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	printf("\n");
	return 0;
}

判断p为NULL时,也可以直接打印开辟失败,不需要调用strerror函数,也不用包含那两个头文件

if (p == NULL)
{
	printf("malloc failed\n");
	exit(-1);
}

calloc函数

void* calloc (size_t num, size_t size);

calloc函数与malloc类似 ,calloc可以看作malloc+memset

 参数num是开辟空间的元素个数,参数size是元素的大小,单位:字节。

函数的功能是为 num 个 size大小 的元素开辟一块空间,并且把空间的每个字节初始化为0。

calloc函数与malloc函数不同点在于:会将开辟的空间都初始化为0(按字节初始化为0)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{	
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return -1;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	printf("\n");
	return 0;
}

下面看运行结果都为0

realloc函数

realloc函数让动态内存管理变得更加灵活,空间不够时可以对动态开辟的空间扩容

void* realloc(void* ptr, size_t szie);

参数ptr为需要扩充动态内存分配的空间的地址

size是 调整之后新大小,返回参数为调整之后的内存起始位置。

realloc在调整内存空间的是存在两种情况:

1.原地扩容

在需要扩容的空间后有足够的空间进行扩容,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

2.异地扩容

原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小 的连续空间来使用。这样函数返回的是一个新的内存地址。

pc指向的空间的数据会迁移到ptr指向的空间,此时不需要将pc的空间free,系统会自动释放。

下图通过两行代码了解什么是异地扩容,可以看到p1和p2的地址发生了变化

p1的值是0x006b56b8  p2的值是0x006bf4d0,所以扩容后的空间地址与原空间地址不同,这就是异地扩容

当然扩容失败就会返回NULL,异常退出了

下面是malloc和realloc的联合使用,我们扩容后要将扩容后的空间再次交给原指针去维护

所以将p=ptr

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
	int* p =(int*) malloc(sizeof(int)*10);
	if (p == NULL)
	{
		printf("malloc faied\n");
		return -1;
	}
	int* ptr = (int*)realloc(p, sizeof(int) * 20);
	if (ptr == NULL)
		return -1;
	p = ptr;
	for (int j = 0; j < 20; j++)
	{
		printf("%d ", p[j]);
	}
 
	printf("\n");
    
    return 0;
}

运行结果可以看到都是随机数,所以realloc函数也不会初始化

可以看出realloc与malloc相似,都不会初始化。同时这也是realloc和malloc的一个特性,

当要扩容的对象为空时,realloc可以当作malloc函数使用。

扩充

我们一般动态开辟的空间都是结构体,下面简单介绍一下开辟结构体类型的空间

我们首先定义了一个结构体类型,里面定义的是int型的数据data,还有一个next型的指针,存放下一节点的地址,这就是数据结构的单链表结构,不了解的小伙伴可以简单看一下

pc指向开辟的一个节点用,p指向开辟的另一个节点用,将pc指向的结构体中的next保存p指向节点的地址

#include <stdio.h>
#include <stdlib.h>
 
typedef struct QueueNode
{
	DataType data;
	struct QueueNode* next;
}QueueNode;
 
int main()
{
	QueueNode* pc = (QueueNode*)malloc(sizeof(QueueNode));
	QueueNode* p = (QueueNode*)malloc(sizeof(QueueNode));
 
	if (pc == NULL && pc == NULL)
	{
		printf("malloc failde\n");
		exit(-1);
	}
	pc->data = 10;
	pc->next = p;
 
	p->data = 20;
	p->next = NULL;
 
	printf("%d %d\n", pc->data, p->data);
	printf("%p %p %p\n", pc->next, p, p->next);
	free(pc);
	free(p);
	pc = p = NULL;
 
	return 0;
}

重点:动态开辟使用完后,一定要记得free,置空。

了解完上面的内容,是不是对动态分配有了更深的理解。

malloc/calloc/realloc区别总结

相同点:

1.都是从堆上申请空间

2.都需要对返回值判空

3.都需要用户free释放

4.返回值类型相同(void*)

5.都需要类型转化

6.底层实现上是一样的,都需要开辟多余的空间,用来维护申请的空间

可以输入以下代码观测内存:

#include <stdio.h>
#include <malloc.h>
int main(){
int *p= (int *)malloc(sizeof(int )*10);
return 0;
}

不同点:

1.函数名字不同和参数类型不同。

2.calloc会对申请空间初始化,并且初始化为0,而其他两个不会。

3.malloc申请的空间必须使用memset初始化

4.realloc是对已经存在的空间进行调整,当第一个参数传入NULL的时候和malloc一样

总结

到此这篇关于C语言中动态内存分配malloc、calloc和realloc函数解析的文章就介绍到这了,更多相关C语言动态内存分配函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言中关于scanf读取缓存区的问题

    C语言中关于scanf读取缓存区的问题

    scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息,接下来通过本文给大家介绍C语言中关于scanf读取缓存区的问题,需要的朋友一起看看吧
    2021-09-09
  • c++与python实现二分查找的原理及实现

    c++与python实现二分查找的原理及实现

    本文介绍了c++与python实现二分查找的原理及实现,二分查找指首先将数组中间值和目标值进行比较,如果相等则返回;如果不相等,则选择中间值左边的一半或者右边的一半进行比较;不断重复直到检索完毕,下文相关资料需要的朋友可以参考一下
    2022-03-03
  • 深入分析C++中几个最不常用的关键字

    深入分析C++中几个最不常用的关键字

    本篇文章是对C++中几个最不常用的关键字进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言与C++中内存管理详解

    C语言与C++中内存管理详解

    本章主要介绍C语言与C++的内存管理,以C++的内存分布作为引入,介绍C++不同于C语言的内存管理方式(new delete对比 malloc free),感兴趣的朋友来看看吧
    2022-04-04
  • C语言深入探究函数的溯源

    C语言深入探究函数的溯源

    函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数
    2022-04-04
  • C++深入讲解new与deleted关键字的使用

    C++深入讲解new与deleted关键字的使用

    这篇文章主要介绍了C++中new与deleted关键字的使用,new在动态内存中为对象分配空间并返回一个指向该对象的指针;delete接受一个动态对象的指针, 销毁该对象, 并释放与之关联的内存
    2022-05-05
  • C语言中枚举与指针的实例详解

    C语言中枚举与指针的实例详解

    这篇文章主要介绍了 C语言中枚举与指针的实例详解的相关资料,希望通过本文大家能够掌握枚举与指针的知识,需要的朋友可以参考下
    2017-09-09
  • C/C++浅析邻接表拓扑排序算法的实现

    C/C++浅析邻接表拓扑排序算法的实现

    这篇文章主要介绍了C/C++对于邻接表拓扑排序算法的实现,邻接表是图的一种链式存储方法,其数据结构包括两部分:节点和邻接点
    2022-07-07
  • 如何将编译过的C++库迅速部署在Visual Studio新项目中

    如何将编译过的C++库迅速部署在Visual Studio新项目中

    本文介绍在Visual Studio中,通过属性表,使得一个新建解决方案中的项目可以快速配置已有解决方案的项目中各类已编译好的C++第三方库的方法,感兴趣的朋友跟随小编一起看看吧
    2024-05-05
  • C++二维数组中的查找算法示例

    C++二维数组中的查找算法示例

    这篇文章主要介绍了C++二维数组中的查找算法,结合实例形式分析了C++二维数组进行查找的原理与具体实现技巧,需要的朋友可以参考下
    2017-05-05

最新评论