【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)

前言:

        本文是对于动态内存管理知识后续的补充,以及加深对其的理解。对于动态内存管理涉及的大部分知识在这篇文章中 ---- 【C进阶】 动态内存管理_Dream_Chaser~的博客-CSDN博客

        本文涉及的知识内容主要在两方面:

  • 简单解析C/C++程序的内存开辟
  • 分析柔性数组的知识点

目录

前言:

C/C++程序的内存开辟区域📍

1.栈区(stack)

2. 堆区(heap)

3. 数据段(静态区)(static)

4. 代码段

柔性数组💨

柔性数组的特点

柔性数组的使用

柔性数组的优势 


C/C++程序的内存开辟区域📍

1.栈区(stack)

在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

2. 堆区(heap)

一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
配方式类似于链表。

3. 数据段(静态区)(static)

存放全局变量、静态数据。程序结束后由系统释放。

4. 代码段

存放函数体(类成员函数和全局函数)的二进制代码。      
📃内存区域划分图:

        📚有了这幅图,我们就可以更好的理解在C语言初识中讲的 static 关键字修饰局部变量的例子了。
  •         实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁
  •         但是被static修饰的变量存放在数据段(静态区)数据段的特点是在上面创建的变量,直到程序结束才销毁,所以生命周期变长。

柔性数组💨

        柔性数组(Flexible Array)是一种在编程语言中用于表示可变长度数组的数据结构。它允许在声明数组时不指定数组的长度,而是在运行时根据需要动态分配内存空间

        柔性数组最常见的应用是在C语言中。在C语言中,柔性数组是一种特殊的结构体成员,其长度可以在结构体实例化之前或之后进行动态调整。

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

啥意思呢,用代码说话

        在vs编译器环境下,以下两种写法均支持

        第一种写法(使用空方括号[ ])是更常见和更符合标准的写法,可以在大多数编译器环境下使用。

struct S
{int n;char c;int arr[];//柔性数组成员
};

        第二种写法(指定大小为0)在某些特定的编译器(vs)扩展中可能有效,但不具有通用性和可移植性

struct S
{int n;char c;int arr[0];//柔性数组成员(指定大小)
};

柔性数组的特点

1️⃣结构中的柔性数组成员前面必须至少一个其他成员

typedef struct st_type
{int i;//必须至少一个其他成员int a[0];//👈柔性数组成员
}type_a;

错误写法:

struct SA
{int arr[];//柔性数组成员
};

2️⃣sizeof 返回的这种结构大小不包括柔性数组的内存

struct S
{int n;char c;int arr[];//柔性数组成员
};
int main()
{printf("%d", sizeof(struct S));
}

🚩8

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

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
int main()
{//arr需要开辟的空间是10个int//                     n与c需要开辟的内存           arr数组需要开辟的内存空间//                           8                         40struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));return 0;
}

图解:

柔性数组的使用

代码实现🎯

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>//柔性数组
struct S
{int n;char c;int arr[];//柔性数组成员
};int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("%s\n",strerror(errno));return 1;}//使用ps->n = 100;ps->c = 'w';int i = 0;for ( i = 0; i < 10; i++){ps->arr[i] = i;}for (i = 0; i < 10; i++){printf("%d\n", ps->arr[i]);}//调整arr数组的大小(注意这是重新改变大小,不是说在原来空间后面增加,比如说原来是48,那么现在就是88)struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));if (ptr == NULL){printf("%s\n,sterror(error)");return 1;}else{ps = ptr;}//再次使用//....//释放free(ps);ps = NULL;printf("%d\n", sizeof(struct S));return 0;
}

调试一下,看看空间大小如何

malloc的空间,58-30=28(16进制),换成十进制刚好为40,刚好是10int的字节大小

柔性数组的优势 

方案一:柔性数组的方案

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>//柔性数组
struct S
{int n;char c;int arr[];//柔性数组成员
};int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("%s\n",strerror(errno));return 1;}//使用ps->n = 100;ps->c = 'w';int i = 0;for ( i = 0; i < 10; i++){ps->arr[i] = i;}for (i = 0; i < 10; i++){printf("%d\n", ps->arr[i]);}//调整arr数组的大小(注意这是重新改变大小,不是说在原来空间后面增加,比如说原来是48,那么现在就是88)struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));if (ptr == NULL){printf("%s\n,sterror(error)");return 1;}else{ps = ptr;}//再次使用//....//释放free(ps);ps = NULL;printf("%d\n", sizeof(struct S));return 0;
}

描述:

malloc 1次 ,free 1次

方案二:结构中指针方案

定义一个指针变量指向一块新的区域,像下面这样

图解: 

 代码实现✨

struct S
{int n;char c;int* arr;
};int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){perror("malloc");return 1;}int* ptr = (int*)malloc(10 * sizeof(int));if (ptr == NULL){perror("malloc2");return 1;}else{ps->arr = ptr;}//使用ps->n = 100;ps->c = 'w';int i = 0;for (i = 0; i < 10; i++){ps->arr[i] = i;}//打印for (i = 0; i < 10; i++){printf("%d ",ps->arr[i]);}//扩容 - 调整arr的大小ptr = realloc(ps->arr,20*sizeof(int));if (ptr == NULL){perror("realloc");return 1;}else{ps->arr = ptr;}//使用//释放free(ps->arr);ps->arr = NULL;free(ps);ps = NULL;return 0;
}

描述: 

malloc 2次,free 2次

        上面的方案一和方案二谁的优势更优呢,显然是方案一

个人的理解:

        从写代码的方面来说,malloc越多,free的越多,空间的维护难度就更高,所以

        方案一实现起来更加简单,空间维护更加简单,容易维护空间,不易出错

        方案二来说,一旦忘记free一次的话,可能会导致内存泄漏等问题,所以维护难度加大,容易出错

        还有区别就是:

        在堆区上申请内存的话,每一次malloc申请的空间,第二次malloc申请的空间跟第一次申请的空间在地址上不一定是连续的,随机性很高,随着malloc申请的数量越多,那么在内存和内存之间留下的空隙就会越多,这种空隙我们叫做为内存碎片

         因为这种内存碎片空间大小比较小一些,那么未来可能被利用到的概率就会比较低一些,所以说,内存碎片越多,那么内存利用率就会越低

总结

①方案一:malloc次数少,内存碎片就会较少,内存的使用率就较高一些

②方案二:malloc次数多,内存碎片就会增多,内存的使用率就下降了

上述 方案 1 和 方案 2 可以完成同样的功能,但是 方法 1 的实现有两个好处:
⛳第一个好处是: 方便内存释放
        如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以, 如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
⛳第二个好处是: 这样有利于访问速度 .
         连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)

         本文结束,如有错误,欢迎指正,感谢支持!

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

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

相关文章

基于VueCli创建自定义项目

1.安装脚手架 (已安装) npm i vue/cli -g2.创建项目 vue create hm-exp-mobile选项 Vue CLI v5.0.8 ? Please pick a preset:Default ([Vue 3] babel, eslint)Default ([Vue 2] babel, eslint) > Manually select features 选自定义手动选择功能 选择vue的版本 3.x …

解决在cmd中输入mongo出现‘mongo‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件的问题~

当我想通过shell连接mongoDB时&#xff0c;输入mongo命令&#xff0c;出现下述错误&#xff1a; 起初我以为我是忘记配置环境变量了&#xff0c;但检查后发现自己配置了&#xff0c;如果你和我是一样的问题&#xff0c;明明配置了环境变量&#xff0c;但上述问题依然没有被解决…

Java“牵手”淘宝商品列表数据,关键词搜索淘宝商品数据接口,淘宝API申请指南

淘宝商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取淘宝商品列表和商品详情页面数据&#xff0c;您可以通过开放平台的接口或者直接访问淘宝商城的网页来获取商品详情信息。以下是两种常用方法的介绍&…

爬虫爬取mp3文件例子

相信训练模型时数据集的获取也是一个很头疼的事情&#xff0c;搞cv领域的可以扛着摄像头架起三脚架拍摄获取&#xff08;以前干过&#xff09;&#xff0c;但是如果是nlp领域的呢&#xff0c;特别是chatgpt等大模型出来后对这类文本等数据的需求更大&#xff0c;如果没有现成的…

Apache实现weblogic集群配置

安装apache&#xff0c;安装相对稳定的版本。如果安装后测试能否正常启动&#xff0c;可以通过访问http://localhost/进行测试。安装Weblogic&#xff0c;参见文档将bea安装目录 weblogic81/server/bin 下的 mod_wl_20.so 文件copy到 apache安装目录下Apache2/modules/目录下A…

联通面试题

一、GC 1.1、目标 GC的主要作用是自动识别和释放不再使用的对象&#xff0c;回收其所占用的内存&#xff0c;以防止内存泄漏和内存溢出的问题。 1.2、如何实现 1.2.1、标记阶段 GC从根对象&#xff08;如线程栈中的引用、静态变量等&#xff09;开始&#xff0c;通过可达性…

构造函数和析构函数(个人学习笔记黑马学习)

构造函数:主要作用在于创建对象时为对象的成员属性赋值&#xff0c;构造函数由编译器自动调用&#xff0c;无须手动调用。析构函数:主要作用在于对象销毁前系统自动调用&#xff0c;执行一些清理工作。 #include <iostream> using namespace std;//对象初始化和清理class…

【MySQL】7、MHA高可用配置及故障切换

MHA概述 MHA&#xff08;Master High Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA用来解决MySQL单点故障问题&#xff1b; MySQL故障切换过程中&#xff0c;能30秒内自动完成故障切换&#xff0c;并保证数据的一致性&#xff0c;实…

通过wordpress 自定义主题的额外CSS删除指定区块

最近用wordpress建站&#xff0c;想要删除指定区块&#xff0c;发现相关的教程蛮少的&#xff0c;作为小白的我搜了相关教程&#xff0c;好像没找到&#xff0c;只能自己慢慢摸索了&#xff0c;看了很多&#xff0c;终于尝试实现了&#xff0c;特记录下&#xff0c;免得自己忘了…

OceanBase 来参加外滩大会了(内附干货PPT)

9 月 7 日至 9 日&#xff0c;2023 inclusion外滩大会在上海黄浦世博园区举办。8 日&#xff0c;由赛迪顾问与 OceanBase 联合主办的外滩大会“分布式数据库助力数实融合”见解论坛圆满落幕。 数字经济加速发展&#xff0c;数字化转型进入深水区&#xff0c;企业对海量数据的存…

级联H桥储能变流器仿真

1.单个H桥模块的工作状态 2.仿真模型 3.仿真结果 3.1逆变电压网侧电压网侧电流 3.2功率跟踪情况 3.3电流跟踪情况 3.4电池SOC变化曲线 3.5相内SOC均衡效果 3.6相间SOC均衡效果 3.7最大零序电压注入与均衡速度 欢迎同行技术交流&#xff0c;联系方式见置顶文章的底部

upload-labs1-21关文件上传通关手册

upload-labs文件上传漏洞靶场 目录 upload-labs文件上传漏洞靶场第一关pass-01&#xff1a;第二关Pass-02第三关pass-03&#xff1a;第四关pass-04&#xff1a;第五关pass-05&#xff1a;第六关pass-06&#xff1a;第七关Pass-07第八关Pass-08第九关Pass-09第十关Pass-10第十一…

uniapp 下拉框数据回显的问题

问题 : 现在是下拉框数据回显不了, 绑定的v-model 原因 : uniui 下拉框数据绑定要是 value text 这种格式的 解决办法: 将获取到的后端数据 转换为 需要的格式 ,再进行绑定 下拉框的数据 遍历

【面试经典150 | 数组】移除元素

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;原地操作 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等…

【C++】day2学习成果:引用、结构体等等。。。

1.封装一个结构体&#xff0c;结构体中包含一个私有数组&#xff0c;用来存放学生的成绩&#xff0c;包含一个私有变量&#xff0c;用来记录学生个数&#xff0c; 提供一个公有成员函数&#xff0c;void setNum(int num)用于设置学生个数 提供一个公有成员函数&#xff1a;void…

并联电容器电容量测试

试验目的 开展并联电容器电容量试验的目的是检查其电容值的变化情况, 以判断电容器内部接线是否正确, 内部各电容单元是否存在断线、 击穿短路或绝缘受潮等现象, 以避免在运行中发生事故。 试验设备 电容电感测试仪 厂家&#xff1a; 湖北众拓高试 试验方法 并联电容器电容量…

python3 简易 http server:实现本地与远程服务器传大文件

在个人目录下创建新文件httpserver.py &#xff1a; vim httpserver.py文件内容为python3代码&#xff1a; # !/usr/bin/env python3 import datetime import email import html import http.server import io import mimetypes import os import posixpath import re import…

PPT架构师架构技能图

PPT架构师架构技能图 目录概述需求&#xff1a; 设计思路实现思路分析1.软素质2.核心输出&#xff08;office输出&#xff09; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,ma…

应用在汽车新风系统中消毒杀菌的UVC灯珠

在病毒、细菌的传播可以说是一个让人敏感而恐惧的事情。而对于车内较小的空间&#xff0c;乘坐人员流动性大&#xff0c;更容易残留细菌病毒。车内缺少通风&#xff0c;残留的污垢垃圾也会滋生细菌&#xff0c;加快细菌的繁殖。所以对于车内消毒就自然不容忽视。 那么问题又来…

Pytest系列-快速入门和基础讲解(1)

前言 目前有两种纯测试的测试框架&#xff0c;pytest和unittestunittest应该是广为人知&#xff0c;而且也是老框架了&#xff0c;很多人都用来做自动化&#xff0c;无论是UI还是接口pytest是基于unittest开发的另一款更高级更好用的单元测试框架 单元测试框架介绍 单元测试…