动态内存管理【malloc,calloc,realloc和free的理解】【柔性数组的概念】

news2024/11/28 22:38:41

一.为什么要有动态内存分配

我们知道,当我们创建变量的时候,我们会向系统申请一定大小的空间内存。比如int a=10或者int arr[10];我就向内存申请了4或者40个字节的大小来存放数据。但是当我们一旦申请好这个空间,大小就无法调整了。但是对于空间的需求,不仅仅就只有上面的情况。有时候我们需要的空间大小只有在程序运行的时候才能知道,那么数组编译时开辟空间的方式就不能满足了。

在C语言中,引入了动态内存开辟,让程序员可以自己申请和释放空间,就比较灵活了。

注意,以下介绍的函数头文件都是stdlib.h

二.malloc,free,calloc和realloc

1.malloc函数的理解

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

1.如果开辟空间成功,则返回一个指向开辟好的空间的指针。

2.如果开辟失败,则返回一个NULL指针,因此我们在使用malloc的时候一定要检查。

3.因为它的返回值是void*,malloc函数不知道返回值的类型,具体在使用时还是程序员来定。

4.如果参数size(单位是字节)为0,malloc的行为是标准没有定义的,取决于编译器。

比如我想开辟能存放5个整数的空间

int main()
{
	int* p = (int*)malloc(20);//这里开辟20个字节的空间,把起始地址放在p里
	if (p == NULL)//判断也没有开辟成功
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p +i) = i + 1;
	}
	return 0;
}

我们可以调试看一下在内存中它是怎么开辟的。

代码运行完毕后:

这些就是malloc函数的使用了。还有我上面写的第4条,明明我用malloc是来申请空间的,结果我要申请0个字节的空间,这就显得有点没用了。

我们需要注意的一点,这些开辟的空间都在内存的哪一个区域?不管是malloc,free,calloc或者realloc这些跟动态内存有关的都存放在内存的堆区。而我们创建的像是局部变量,形式参数这些是在栈区。而静态变量,全局变量,这些在静态区。

2.free函数的理解

这个函数是专门用来做动态内存的释放和回收的。

1.如果参数ptr指向的空间不是动态内存开辟的,那free函数的行为的未定义的。

2.如果参数ptr是NULL指针,则函数什么事也不做。

也就是说,我想释放哪里的空间,就把这一块空间的起始地址给这个函数的参数。

free的作用就是把空间的使用权限还给了操作系统,还是上面的代码:

#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(20);//这里开辟20个字节的空间,把起始地址放在p里
	if (p == NULL)//判断也没有开辟成功
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p +i) = i + 1;
	}
	free(p);
	p = NULL;
	return 0;
}

调试运行之后是这样的:

注意,我们在把p指向的那一块空间给释放了之后,p指针还是存在的,但是它没有指向的东西了,此时的p就是一个野指针,那我们就必须给这个野指针一条绳子NULL来栓住它。

3.calloc函数的理解

calloc函数也是用来动态申请空间的,但是它的用法跟malloc不太一样。

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

2.与malloc的区别就是,malloc在开辟空间的时候没有初始化这个功能。

举个例子:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p = NULL)
	{
		perror("calloc");
		return 1;
	}
	return 0;
	free(p);
	p = NULL;
}

这里我没有进行赋值操作,但是在内存中这些值就已经变成了0。

其他的地方跟malloc是一样的,在释放空间后也是需要给上一个NULL。

4.realloc函数的理解

这个函数是基于动态内存的,如果我们在开辟空间的时候,觉得我们申请的空间太大了或者太小了,为了能够合理的使用内存,我们可以使用realloc函数实现对动态开辟内存大小的调整。

1.ptr是要调整的内存地址,size是调整之后的大小。

2.返回值是调整之后的内存起始位置。

3.这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

4.realloc函数在调整时有两种情况,一种是原来的空间后面有足够的空间大小,另一种是后面的空间不够了。

我先简单写一下代码,简单说一下第四点会出现的问题。

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(5, sizeof(int));//这里原本是20个字节的大小
	if (p = NULL)
	{
		perror("calloc");
		return 1;
	}
	int* ptr=(int*)realloc(p, 40);//这里调整为40个字节
	if (ptr != NULL)//这里我没有直接把开辟空间的起始地址给p,就是害怕万一开辟空间失败了,原来的空间也没了
	{
		p = ptr;//这里空间调整成功了就可以使用我们开辟的40个字节的空间了
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i + 1;
		}
		free(p);//一定要记得释放,否则会存在内存泄漏的问题
		p = NULL;//释放空间了一定要置为空指针
	}
	else
	{
		perror("realloc");
	}
	return 0;
}

 这里就是开辟空间扩大的情况。

情况一:原内存之后有足够的空间的话,会直接在原来的空间的后面再开辟20个字节,凑够40个字节。

情况二:原内存之后没有足够的空间的话,这个函数会在堆区的内存里找一个新的空间,并且是满足我们所要开辟的空间的,而且会把原来空间的数据拷贝一份到新的空间,原来的空间释放掉,并且会把新的空间的起始地址返回。

情况三:如果调整失败了,直接返回NULL。

注意:realloc不仅仅可以调整空间的,它也可以开辟空间,我们想一下,如果我给ptr的参数是一个空指针呢?

#include<stdlib.h>
int main()
{
	realloc(NULL, 20);//这个等价于malloc(20)
	return 0;
}

以上就是动态空间分配需要使用到的函数。

5.总结4个函数

当我们在申请空间后,不再用这块空间了,虽然,当程序结束的时候,操作系统会回收这一块空间,但最好是我们主动去用free释放,尽量做到谁(函数)申请的空间谁释放。因为如果我的这块空间一直不退出的话这一块内存就一直被占用着,谁也用不了。如果不能释放,要告诉使用的人,要记得释放。

三.柔性数组

关于柔性数组,有几点需要介绍一下:

1.它存在于结构体中,是结构体的最后一个成员

2.最后的一个成员是数组,而且没有指定大小

struct S
{
	char c;
	int i;
	int arr[];//这个就是柔性数组,并没有规定具体的大小或者写成int arr[0]
};

这就是柔性数组

1.柔性数组的特点

1.结构体里的柔性数组成员前面必须至少有一个其他成员

2.sizeof计算这样含柔性数组大小的时候,不包括柔性数组的内存

3.包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

关于前两点

直接就只是i的大小。

再来看第三点:

struct S
{
	int i;
	int arr[];//这个就是柔性数组,并没有规定具体的大小
};
#include <stdio.h>
int main()
{
	struct S* ps=(struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
    free(ps);
    p=NULL;
	return 0;
}

除了我要开辟的int大小的空间,后面我又加了一个5 * sizeof(int)这个是我要额外开辟的空间。

我们既然是用malloc开辟的空间,那么我们是不是就可以使用realloc来改变这一块空间,随便怎么变大变小。对应到这个数组上,我们不就是把这个数组变成“柔性”了吗?

2.柔性数组的使用

了解了它的一些基本特点,还有前面的几个函数,使用起来也就很简单了。

struct S
{
	int i;
	int arr[];//这个就是柔性数组,并没有规定具体的大小
};
#include <stdio.h>
int main()
{
	struct S* ps=(struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
	if (ps == NULL)//没有开辟成功
	{
		return 1;
	}
	ps->i = 100;
	int a = 0;
	for (a = 0; a < 5; a++)
	{
		ps->arr[a] = a + 1;
	}
	struct S* ret = (struct S*)realloc(sizeof(struct S) + 10 * sizeof(int));//调整为44个字节大小
	if (ret != NULL)
	{
		ps = ret;
	}
	free(ps);
	ps = NULL;
	return 0;
}

到这里,关于动态内存管理的相关知识就已经讲完了。感谢大家的观看,如有错误,请大家多多指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1556384.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux部署Kafka2.8.1

安装Jdk 首先确保你的机器上安装了Jdk&#xff0c;Kafka需要Java运行环境&#xff0c;低版本的Kafka还需要Zookeeper&#xff0c;我此次要安装的Kafka版本为2.8.1&#xff0c;已经内置了一个Zookeeper环境&#xff0c;所以我们可以不部署Zookeeper直接使用。 1、解压Jdk包 t…

缓存和缓存的常用使用场景

想象一下,一家公司在芬兰 Google Cloud 数据中心的服务器上托管一个网站。对于欧洲用户来说,加载可能需要大约 100 毫秒,但对于墨西哥用户来说,加载需要 3-5 秒。幸运的是,有一些策略可以最大限度地减少远程用户的请求延迟。 这些策略称为缓存和内容交付网络 (CDN),它们是…

HarmonyOS实战开发-使用List组件实现导航与内容联动的效果。

1 卡片介绍 使用ArkTS语言&#xff0c;实现一个导航与内容二级联动的效果。 2 标题 二级联动&#xff08;ArkTS&#xff09; 3 介绍 本篇Codelab是主要介绍了如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能&#xff1a; 切换左侧导航&#xff…

OSCP靶场--Sorcerer

OSCP靶场–Sorcerer 考点(feroxbuster目录扫描zip包隐藏文件发现公钥私钥公钥覆盖私钥登陆suid start-stop-daemon提权) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.216.100 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.or…

nodejs下载安装以及npm、yarn安装及配置教程

1、nodejs下载安装 ​ 1.1、使用nodejs版本管理工具下载安装&#xff0c;可一键安装、切换不同nodejs版本&#xff0c; nvm-setup.zip&#xff1a;安装版&#xff0c;推荐使用 本次演示的是安装版。 1、双击安装文件 nvm-setup.exe 选择nvm安装路径 例如&#xff1a;E:\Soft…

STL中容器、算法、迭代器

STL标准模板库封装了常用的数据结构和算法&#xff0c;让程序员无需太关心真实的数据结构实现。 容器 容器&#xff1a;用来存放数据的。 STL容器就是将运用最广泛的的一些数据结构实现出来。 常用的数据结构有&#xff1a;数组、链表、树、栈、队列、集合、映射表。 这些…

印度神体系与编程思维

印度神体系中存在三大主神&#xff1a;至高神梵天、毗湿奴以及湿婆。 1.神的类型抽象与神性优先级&#xff1a; 每一个神都掌握着世间中所存在的规律&#xff0c;比如天界里因陀罗&#xff08;帝释天&#xff09;等神掌控风火水电。换句话说&#xff0c;每一个可以抽象出来的世…

怎么把照片容量变小?图片压缩技巧分享

照片文件通常占据大量存储空间&#xff0c;特别是在拍摄高分辨率照片或大量照片的情况下&#xff0c;通过减小照片文件大小&#xff0c;可以节省设备内部存储或外部存储介质上的空间&#xff0c;使您能够容纳更多的照片。 打开压缩网站&#xff0c;点击选择图片压缩&#xff0…

JUC高并发编程详解

大家好&#xff0c;欢迎来到这篇关于JUC&#xff08;Java Util Concurrent&#xff09;高并发编程的博客&#xff01;在这个数字时代&#xff0c;我们的软件需求越来越庞大&#xff0c;而对于高并发编程的需求也日益迫切。在Java的世界里&#xff0c;JUC就像一位强大的武士&…

Mamba: Linear-Time Sequence Modeling with Selective State Spaces(论文笔记)

What can I say? 2024年我还能说什么&#xff1f; Mamba out! 曼巴出来了&#xff01; 原文链接&#xff1a; [2312.00752] Mamba: Linear-Time Sequence Modeling with Selective State Spaces (arxiv.org) 原文笔记&#xff1a; What&#xff1a; Mamba: Linear-Time …

线程池-2:runWorker分析-1

为何runWorker中在task被当前worker中的当前线程获取到准备执行task时需要进行worker.lock()? 如下图&#xff1a; 1、某个worker中的run逻辑只会被worker中包装的线程进行执行&#xff1b; 2、按理说&#xff1a;不会存在多个线程并发执行同一个worker中的runWorker()逻辑&a…

蓝桥杯真题Day41 倒计时13天 纯练题,该开始复习知识点了!

蓝桥杯第十二届省赛真题-分果果 题目描述 小蓝要在自己的生日宴会上将 n 包糖果分给 m 个小朋友。每包糖果都要分出去&#xff0c;每个小朋友至少要分一包&#xff0c;也可以分多包。 小蓝将糖果从 1 到 n 编号&#xff0c;第 i 包糖果重 wi。小朋友从 1 到 m 编号。每个小朋…

Codeforces Round 838 (Div. 2) D. GCD Queries

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e9, maxm 4e4 5; co…

SpringCloud下的微服务应用技术(结尾篇)

六. Feign远程调用 6.1 替代RestTemplate RestTemplate调用问题&#xff1a;代码可读性差&#xff0c;参数复杂且URL难维护。 Feign是一个声明式的HTTP客户端&#xff0c;官方地址&#xff1a;GitHub - OpenFeign/feign: Feign makes writing java http clients easier 它可…

安装DPDK环境

安装DPDK环境 下载解压源码 wget https://fast.dpdk.org/rel/dpdk-19.08.2.tar.xz tar -xcf ./dpdk-19.08.2.tar.xz安装源码 1.处理库文件 编译库文件 ./dpdk-setup.sh 根据操作系统选择对应gcc库文件2.设置环境变量 配置多网卡队列和巨页 ethernet1.virtualDev "vm…

车载以太网AVB交换机 TSN交换机 时间敏感网络 11口 千兆 SW2000TSN

目录 一、TSN时间敏感交换机概述 二、产品介绍 SW2000M/H TSN 1、产品框架 2、产品特点与参数 产品特点 产品参数 3、配置与使用 4、常用连接方式 4.1 双通道作为监控和数据采集器&#xff0c;采集两个设备间的通信数据&#xff08;Bypass功能&#xff09; 4.2 试验搭…

如何用Python脚本自动发送邮件?

目录 1. 基础知识 1.1. SSH&#xff08;Secure Shell&#xff09;协议 1.2. SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;协议 1.3. SSH协议与SMTP协议之间的关系 2. QQ邮箱设置 2.1. 开启SMTP服务 2.2. 编写脚本 3. 测试成功 1. 基础知识 邮件的发送过…

XXE漏洞知识及ctfshow例题

XXE漏洞相关知识 XXE全称为XML Enternal Entity Injection 中文叫xml外部实体注入 什么是xml 简单了解XML&#xff1a; &#xff08;xml和html的区别可以简易的理解成&#xff1a;xml是用来储存数据和传输数据的而html是用来将数据展现出来&#xff09; XML 指可扩展标记语…

UE中:200W个对象单场景实现(待更新)

实现背景&#xff1a;需要显示城市级的行人以及地理市级范围内的路灯的状态&#xff0c;行人需要有状态以及位置的更新&#xff0c;路灯只需要状态的更新&#xff0c;二者都不需要物理 方案1概述&#xff1a;Niagara粒子系统实现 实际效果展示 UE5 集群模拟&#xff08;20W&a…

pmp培训机构哪个比较好?国内10大热门PMP培训机构是哪些?

热门PMP培训机构推荐&#xff0c;PMP备考选择威班就是选择了高通过率 PMP热门培训机构方面我还是比较推荐威班的&#xff0c;当时选择的时候有人推荐我&#xff0c;也了解了很多&#xff0c;各种科普各种对比选择&#xff0c;最后还是选择了威班。经过体验他们的通过率比较靠谱…