【C语言必学知识点七】什么?还有人不知道什么是柔性数组?还不速来!!!

动态内存管理——详细解读柔性数组

  • 导读
  • 一、什么是柔性数组
  • 二、柔性数组的特点
  • 三、柔性数组的使用
  • 四、柔性数组的优势
  • 结语

封面

导读

大家好,很高兴又和大家见面啦!!!

在上一篇内容中我们介绍了C/C++程序中的内存分区,在C/C++程序中内存从高地址到低地址的分区依次为:

  • 内核空间:存储内核代码,内核代码不能进行读/写操作
  • 栈区:存储函数体内创建的对象,如变量、函数返回值、数组、指针等,空间从高地址向低地址增长;
  • 内存映射段:存储文件映射、动态库、匿名映射等数据
  • 堆区:由动态函数进行管理的空间,空间从低地址向高地址增长
  • 数据段:存储全局数据、静态数据
  • 代码段:存储可执行代码、只读常量等数据

正因为动态函数管理的内存空间与指针所在的空间不是同一个空间,因此 free 函数不能够释放与指针所在空间相同的内存空间,即指针指向的栈区空间,如数组空间。

malloc函数在进行空间申请时,会执行三步操作:

  1. 在堆区空间中查找空间
  2. 判断空间是否可用
  3. 判断空间大小是否为指定大小

因此free函数在进行空间释放时,在确认该空间是否为有效空间时,同样是进行的这三部判断:

  1. 空间地址是否在堆区
  2. 空间是否被使用
  3. 空间大小是否为指定大小

而我们在使用动态函数时,如果不注意对应函数的使用规则,就会导致一系列的问题:

  1. 空间申请失败时,对空指针进行解引用操作
    • 解决方案:在完成空间申请后,及时对接收返回值的指针进行判空操作
  2. 使用空间时,对已开辟好的空间进行越界访问
    • 解决方案:对开辟好的空间进行访问时,边界不能够超过申请的空间大小
  3. 使用空间后,未及时释放堆区空间导致内存泄漏
    • 解决方案:
      • 进行扩容时,通过临时指针接收扩容后的空间地址,并对其进行及时的判空操作
      • 函数返回时,检查不再使用的堆区空间是否被释放
  4. 释放空间时,指针指向的空间不是堆区的空间
    • 解决方案:在进行空间释放前,检查指针名是否有误,指针指向的空间是否为堆区空间
  5. 释放空间时,指针指向的地址不是该空间的起始地址
    • 解决方案:在进行空间访问时,不要改变指向空间起始地址的指针
  6. 释放空间时,对同一块空间进行多次释放
    • 解决方案:
      • 空间申请时,确保calloc/mallocfree是一一对应的关系:
      • 空间扩容后,及时的改变原指针的指向,确保指针指向的是扩容好的内存空间地址

为了避免这些问题的出现,所以我们需要在使用动态函数前,先了解一个各个函数的用法,避免对函数使用不当而导致出现上述错误。

经过前面的内容学习,形象大家都对动态内存管理有了一个基础的认知,接下来我们就看来看一下动态内存管理的一种实际的应用——柔性数组。

一、什么是柔性数组

柔性数组(flexible array),相信大部分朋友都和我一样,在这之前完全没有听说过,甚至连使用都很少,但是,它是确实存在的一个概念。

C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做【柔性数组】成员

typedef struct SoftArr {int* pa;//整型指针int pb[0];//柔性数组
}SfA;

上面展示的就是一种柔性数组的例子,对于有些编译器而言,上述的这种编译方式是编译器会报错,因此我们也可以将其改写为:

typedef struct SoftArr {int* pa;//整型指针int pb[];//柔性数组
}SfA;

柔性数组只存在于结构体中,但是它本身的数组大小为0,即不占内存空间,如下所示:

柔性数组
柔性数组的具体大小会在在结构体变量创建时,通过malloc来进行分配,因此,我们可以将其看做是一个大小可以改变的数组。

二、柔性数组的特点

柔性数组存在以下特点:

  • 结构中的柔性数组成员前面必须至少一个其他成员
  • sizeof 返回的这种结构大小不包括柔性数组的内存
  • 包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大
    小,以适应柔性数组的预期大小

我们应该如何来理解这些特点呢?

首先我们要知道,结构体是一些值的集合,这些值可以是不同的数据类型,它们被称为结构体成员。

在包含柔性数组的结构体中,成员数量至少是有2个,如上例所示的整型指针与柔性数组,而且柔性数组的位置一定是结构体中的最后一个成员。

结构体在进行内存分配时,根据内存对齐的规则,每个成员都会分配到特定的位置,但是柔性数组的大小未知的,如果我们将放在了其它成员的中间,那么位于柔性数组之后的成员要被分配的位置就不可预测了,因此我们需要将大小确定的成员优先放入内存中,这样柔性数组的大小就可以随着实际的情况来进行确定。

其次正因为柔性数组的大小是不确定的,我们就可以认为柔性数组的初始大小为0,这样当我们通过sizeof来计算结构体大小时,会将柔性数组的大小认定为0,即sizeof计算的只是柔性数组之前的所有成员组成的结构体的总大小,并不包括柔性数组的大小;

最后包含柔性数组的结构体,在创建变量时,只能够创建对应类型的指针变量,该指针指向的空间,是可以改变的堆区空间,即通过malloccalloc或者realloc申请的空间。

对柔性数组的特点有了一个初步的理解后,接下来我们就来看一下我们应该如何使用柔性数组;

三、柔性数组的使用

使用柔性数组时,实际上就是创建一个该结构类型的指针变量,并在堆区申请空间,如下所示:

typedef struct SoftArr {int* pa;//整型指针int pb[0];//柔性数组
}SfA;//柔性数组
void test1() {printf("sizeof(SfA) = %d\n", sizeof(SfA));SfA* p = (SfA*)calloc(sizeof(SfA) + 5 * sizeof(int), 1);assert(p);printf("p->pa = %p\n", p->pa);for (int i = 0; i < 5; i++) {printf("p->pb[%d] = %d\n", i, p->pb[i]);}free(p);
}

这里我们要注意的是我们在申请空间时,sizeof(SfA) 表示的是柔性数组之前的成员需要分配的空间大小,之后的5 * sizeof(int)才是为柔性数组分配的空间大小。因此我们在申请空间时,是按字节进行申请的,而不是元素所占空间的大小,所以,使用malloc的话会更加容易理解一点,如果和我一样使用calloc,那就需要注意第二个参数的大小为1。

下面我们就来运行一下,如下所示:

柔性数组2
可以看到,此时我们成功的为该结构体申请了空间,并对结构体中的成员进行了访问。当然,我们还可以通过realloc来为柔性数组进行扩容,如下所示:

柔性数组3
相信大家应该知道如何来使用柔性数组了。

四、柔性数组的优势

在上例中,我创建的结构体是由整型指针与柔性数组组成的集合,之所以选择这两个作为结构体成员,是因为它们都能够通过动态函数来申请空间,如下所示:

柔性数组4
可以看到,指针成本变量与柔性数组是可以完成同样的工作的,而且指针变量还没有一定是结构体最后一个成员的限制,这样看起来似乎比柔性数组方便多了,为什么我们不直接采用指针变量的方式来实现呢?

实际上我们从最后的空间释放就可以到,如果采用指针变量的话,在进行空间释放时,我们需要进行两次空间释放,一次是指针变量成员指向的内存空间,一个只是结构体指针变量指向的内存空间,且它们释放的顺序还不能改变。因此就空间释放这一点来说,采用柔性数组会比采用指针变量要方便很多。

当我们通过柔性数组实现时,我们像内存空间申请的是一块连续的空间,而通过指针变量实现时,我们则是像内存空间申请了两块空间——结构体指针变量指向的内存空间与成员指针变量指向的内存空间。

在前面的内容中我们有介绍过,对于结构体而言,其成员在内存空间中都是会对齐到对应的边界上,因此我们要找到结构体中的每一个成员时,就需要根据成员的偏移量进行查找。

  • 当结构体中的最后一个成员是柔性数组时,我们只需要找到了柔性数组的起始地址,就可以开始正常的访问数组中的元素;
  • 而当结构体中的最后一个成员是指针变量时,我们需要先找到该成员的地址,再由该成员的空间中存储的地址找到其所指向的内存空间,才能访问空间内的元素。

就访问速度上来看,使用柔性数组的内存访问速度要优于使用指针变量的内存访问速度。因此当我们要在结构体中存储一些同类型的值时,我们使用柔性数组会优于指针变量。

其实这里的问题就是在比较结构体中的数组与指针,给大家推荐一篇文章:【C语言结构体里的成员数组和指针】。这篇文章是由陈皓大佬写的,文章内容深度解析了结构体中的数组和指针的问题。

结语

今天的内容到这里就全部结束了,如果大家喜欢博主的内容,可以点赞、收藏加评论支持一下博主,当然也可以将博主的内容转发给你身边需要的朋友。

【C语言必学知识点】这一专栏的全部内容也在今天就全部完结了,这个专栏的内容主要是以C语言中我们需要学习的基础语法与基础知识体系为主,是各位和我一样的初学者必须要学习的知识点。

之后,博主将会在【C语言加油站】专栏中继续为大家带来C语言中的相关知识解读,感兴趣的朋友可以关注以下该专栏。

对于计算机的学习,只了解计算机语言的基础语法是完全不够用的,因此后续我也会在学习408的过程中同步开设相应的博客专栏来分享我对已学知识点的记录以及我对这些知识点的个人见解。大家有和我一样要开始学习408的朋友,或者正在学习408的朋友可以关注一下对应的专栏哦!

最后感谢各位朋友的支持,咱们下一篇再见!!!

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

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

相关文章

C++11 --- 可变参数模板

序言 不知道大家有没有细细研究过在 C 语言 中的 printf 函数&#xff0c;也许我们经常使用他&#xff0c;但是我们可能并不是那么了解他。先看一下调用格式&#xff1a;int printf ( const char * format, ... );&#xff0c;在这里的 format 代表我们的输出格式&#xff0c;后…

欧拉下搭建第三方软件仓库—docker

1.创建新的文件内容 切换目录到etc底下的yum.repos.d目录&#xff0c;创建docker-ce.repo文件 [rootlocalhost yum.repos.d]# cd /etc/yum.repos.d/ [rootlocalhost yum.repos.d]# vim docker-ce.repo 编辑文件,使用阿里源镜像源&#xff0c;镜像源在编辑中需要单独复制 h…

华为防火墙 nat64

如果设备接收到的IPv6报文的前缀是设备为NAT64定义的前缀&#xff0c;说明报文的目的地址是IPv4网络&#xff0c;报文将经过NAT64处理后被转发至IPv4网络。 如果设备接收到的IPv6报文的前缀不是设备为NAT64定义的前缀&#xff0c;说明报文的目的地址是IPv6网络&#xff0c;报文…

网站钓鱼——挂马技术手段介绍

更多网安实战内容&#xff0c;可前往无问社区查看http://wwlib.cn/index.php/artread/artid/10194.html 网站挂马目前已经成为流氓软件以及红队人员快速获取目标主机权限的常用手段之一&#xff0c;在长时间的实战中也是出现了层出不穷的钓鱼方法&#xff0c;这次分享一下实际…

【北京迅为】《STM32MP157开发板使用手册》-第十三章 编译QtE5.12文件系统

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

内网中的RDP利用

学习参考 https://www.freebuf.com/articles/network/276242.html能跟着实操的都实操一下。熟悉一些命令&#xff0c;过程。 实验环境&#xff1a;win2008&#xff0c;192.168.72.139 两个用户&#xff1a; administrator&#xff0c;shizuru RDP服务 确定/开启 RDP服务确…

Chainlit集成Mem0使用一个拥有个性化AI记忆的网页聊天应用

前言 Mem0 简介&#xff0c;可以看我上一篇文章《解决LLM的永久记忆的解决方案-Mem0实现个性化AI永久记忆功能》。本篇文章是对Mem0 实战使用的一个示例。通过Chainlit 快速实现ui界面和open ai的接入&#xff0c;通过使用Mem0 实现对聊天者的对话记录的记忆。 设计实现基本原…

828华为云征文|部署多媒体流媒体平台 Plex

828华为云征文&#xff5c;部署多媒体流媒体平台 Plex 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 性能模式1.3 计费模式 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Plex3.1 Plex 介绍3.2 Docker 环境搭建3.3 Plex 部署3.4 Plex 使…

张家辉新作《重生》内地票房逆袭

由张家辉领衔主演的电影《重生》在票房大获成功&#xff0c;击败多部同期中西强片&#xff0c;成为今年暑期档的最大黑马。张家辉在片中饰演的角色原本拥有幸福家庭&#xff0c;为了复仇走上亡命之徒的道路&#xff0c;影片中他再度展现了影帝级别的演技&#xff0c;受到网民和…

CCF推荐A类会议和期刊总结(计算机网络领域)- 2022

CCF推荐A类会议和期刊总结&#xff08;计算机网络领域&#xff09;- 2022 在中国计算机学会&#xff08;CCF&#xff09;的推荐体系中&#xff0c;A类会议和期刊代表着计算机网络领域的顶尖水平。这些会议和期刊不仅汇集了全球顶尖的研究成果&#xff0c;还引领着该领域的前沿发…

合碳智能 × Milvus:探索化学合成新境界——逆合成路线设计

合碳智能&#xff08;C12.ai&#xff09;成立于2022年&#xff0c;致力于运用AI和具身智能技术&#xff0c;为药物研发实验室提供新一代智能化解决方案&#xff0c;推动实验室从自动化迈向智能化&#xff0c;突破传统实验模式与人员的依赖&#xff0c;解决效率和成本的瓶颈&…

解决浏览器自动将http网址转https

删除浏览器自动使用https的方式 在浏览器地址栏输入&#xff1a;chrome://net-internals/#hsts PS:如果是edge浏览器可输入&#xff1a;edge://net-internals/#hsts 在Delete domain security policies搜索框下&#xff0c;输入要删除的域名,然后点击delete 解决方法&#…

回收玻璃减薄中的氢氟酸

回收玻璃减薄中的氢氟酸是一个重要的环保和资源再利用环节。在玻璃减薄过程中&#xff0c;氢氟酸作为主要的化学蚀刻剂&#xff0c;与玻璃基板表面的二氧化硅等成分发生反应&#xff0c;实现玻璃的减薄。然而&#xff0c;随着反应的进行&#xff0c;氢氟酸的浓度会逐渐降低&…

MyQql性能诊断与实践

获取更多免费资料&#xff0c;见下图

证书学习(四)X.509数字证书整理

目录 一、X.509证书 介绍1.1 什么是 X.509证书?1.2 什么是 X.509标准?1.3 什么是 PKI?二、X.509证书 工作原理2.1 PKI 的基础——加密算法2.2 PKI 证书编码三、X.509证书 结构3.1 证书字段3.2 证书扩展背景: 我们在日常的开发过程中,经常会遇到各种各样的电子证书文件,其…

新电脑Win11系统想要降级为Win10怎么操作?

前言 现在的电脑大部分都是Windows 11系统&#xff0c;组装机还好一些&#xff0c;如果想要使用Windows 10&#xff0c;只需要在安装系统的时候选择Windows 10镜像即可。 但是对于新笔记本、厂商的成品机、一体机来说&#xff0c;只要是全新的电脑&#xff0c;基本上都是Wind…

快速入门游戏领域,开发游戏需要哪些技术?

在这个充满创意和技术的时代&#xff0c;游戏行业成为众多创新人才追求梦想的热土。对于准备踏入这个充满挑战与机遇的领域的新人来说&#xff0c;了解游戏开发流程是至关重要的。 游戏市场蓬勃发展&#xff0c;游戏行业未来行情可观&#xff0c;在这个充满创意和技术的时代&a…

8. GIS数据分析师岗位职责、技术要求和常见面试题

本系列文章目录&#xff1a; 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…

vue3 前端实现pdf打印预览 printjs

在utils建print.ts文件 interface PrintFunction {extendOptions: Function;getStyle: Function;setDomHeight: Function;toPrint: Function; }const Print function (dom, options?: object): PrintFunction {options options || {};// ts-expect-errorif (!(this instanc…

电脑技巧:如何在Win11电脑上调整设置,让屏幕更加护眼?

目录 一、调整屏幕亮度 二、启用夜间模式 三、调整色彩设置 四、使用第三方护眼软件 五、保持良好的用眼习惯 总结 随着长时间使用电脑的人越来越多,护眼问题也变得越来越重要。Win11作为更新的操作系统,提供了更多的设置选项来帮助我们保护眼睛。本文将详细介绍如何在…