当前位置: 首页 > news >正文

C/C++中内存开辟与柔性数组

C/C++中内存的开辟

        在C中,我们都知道有三个区:

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

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

       3.静态区(全局区)(static):存放全局变量、静态数据程序结束后由系统释放

但是其实要更加细分,区域可以分为:

        C/C++程序内存分配的几个区域:

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

         2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分 配方式类似于链表。

        3. 数据段(静态区)(static):存放全局变量、静态数据。程序结束后由系统释放。

        4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。

        实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。

        但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序 结束才销毁 所以生命周期变长。

柔性数组:
       

        柔性数组大家可能都没听说过,但是它是真实存在的,前面介绍过结构体的大小应该怎么去计算,这里涉及到大小的计算:

例如:

#include<stdio.h>
typedef struct pc
{char a;int b;int arr[];
}pc;
int main()
{printf("%d", sizeof(pc));return 0;
}

        这组代码的结果应该是什么?

前面介绍了结构体大小的计算:

        例如:

        

#include<stdio.h>
typedef struct pc
{char a;int b;
}pc;
int main()
{printf("%d", sizeof(pc));return 0;
}

他的大小是:

        

大小是8个字节。

这两组代码答案都是8,第一组代码加上了一个大小未知的整型数组,结果和没有加是一样的!!!

此时在结构体中大小未知的数组就被称之为柔性数组!!

        那么柔性数组的大小究竟是多少呢?

柔性数组的特点:


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

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

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

先用图来讲解:

                假设我要开辟20个字节,这20个字节有8个字节是除去数组arr结构体的大小

剩下的12个字节都会留给arr数组,所以arr数组的大小为12个字节!

综上arr数组的大小可以自己改变。

代码如下:
        

#include<stdio.h>
#include<stdlib.h>
typedef struct pc
{char a;int b;int arr[];
}pc;int main()
{pc* ptr = ( pc*)malloc(sizeof(pc) + 12);if (ptr == NULL){perror("malloc");return 1;}return 0;
}

当然结构体我们也可以这样写(不用柔性数组):

        

int main()
{pc* ptr = (pc*)malloc(sizeof(pc) + 12);if (ptr == NULL){perror("malloc1");return 1;}ptr->arr = malloc(12);if (ptr->arr == NULL){perror("malloc2");return 1;}int* pr = (int*)realloc(ptr->arr, 8);if (pr != NULL){ptr->arr = pr;;}else{perror("realloc");return 1;}free(ptr);ptr = NULL;free(pr);pr = NULL;return 0;
}

这个效果和柔性数组的效果是一样的!!

那么柔性数组的好处在哪?

第一个好处是:方便内存释放 如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给 用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你 不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好 了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉

第二个好处是:这样有利于访问速度. 连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正 你跑不了要用做偏移量的加法来寻址)

相关文章:

  • 鸿蒙 如何将base64的图片保存到相册
  • C#操作MySQL从入门到精通(18)——使用组合查询
  • [12] 使用 CUDA 进行图像处理
  • Docker(一)-认识Docker
  • 【PL理论】(24) C- 语言:有块的作用域 | 更新的语法 | 新的语义域 | 环境 vs. 内存
  • SQLite JDBC驱动程序
  • SQL RIGHT JOIN 详解
  • 蚂蚁集团:2023年科研投入211.9亿元
  • LabVIEW图像采集处理项目中相机选择与应用
  • 目标检测算法YOLOv10简介
  • whisper 模型源码解读
  • JavaScript-转换成布尔型
  • 短视频矩阵系统/源码搭建---拆解热门视频功能开发上线
  • 如何选择合适的大模型框架:LangChain、LlamaIndex、Haystack 还是 Hugging Face
  • 【Linux硬盘读取】Windows下读取Linux系统的文件解决方案:Linux Reader4.5 By DiskInternals
  • CAP理论的例子讲解
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • HTML5新特性总结
  • leetcode46 Permutation 排列组合
  • Lucene解析 - 基本概念
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • OSS Web直传 (文件图片)
  • python学习笔记 - ThreadLocal
  • SwizzleMethod 黑魔法
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • TypeScript实现数据结构(一)栈,队列,链表
  • underscore源码剖析之整体架构
  • vue总结
  • 从0实现一个tiny react(三)生命周期
  • 从输入URL到页面加载发生了什么
  • 大型网站性能监测、分析与优化常见问题QA
  • 高度不固定时垂直居中
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 前端性能优化——回流与重绘
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 为视图添加丝滑的水波纹
  • 协程
  • ​​​【收录 Hello 算法】9.4 小结
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • $().each和$.each的区别
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (蓝桥杯每日一题)love
  • (十一)手动添加用户和文件的特殊权限
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • (转)大型网站架构演变和知识体系
  • (转)负载均衡,回话保持,cookie
  • .net Application的目录
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .Net 代码性能 - (1)
  • :“Failed to access IIS metabase”解决方法
  • ?.的用法
  • @Autowired标签与 @Resource标签 的区别
  • @RequestBody与@ResponseBody的使用
  • [ 云计算 | AWS 实践 ] 基于 Amazon S3 协议搭建个人云存储服务