我眼中的‘C’——动态内存+柔型数组

简介: 我眼中的‘C’——动态内存+柔型数组

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


c语言的内存区域可以划分为5个区——内核空间,栈,内存映射段,堆,数据段和代码段。


请看我作的图。


image.png


在学习计算机语言时,我们在语言层面一般把内存划分为下面几个区域——栈区,堆区和静态区。


栈区对应上面的栈,堆区对应上面的堆,而静态区所对应的是静态段。


内存中有一段区域是不允许用户来使用的,这块区域就是内核空间,内核空间是留给操作系统来使用的,用户代码是不能读写的。


我们写的代码编译之后会留下汇编指令,这些指令需要存储起来才能正常运行,储存这些指令的地方就是代码段了。


栈区(stack):主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。如函数执行时,函数的形参以及函数内的局部变量是分配在栈区的,函数运行结束后,形参和局部变量去栈(自动释放)。栈内存分配运算内置与处理器的指令集中,效率高但是分配的内存空间有限。上面代码里红框的部分全都存储在栈区。

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

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

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

ptr1指向一段空间,这块空间是由malloc来申请的,malloc申请的空间在堆区储存,ptr1是维护那段空间的,它所储存的地址所指向的空间存储在堆区,但是ptr1本身是局部变量,存储在栈区。calloc和realloc同理。


柔性数组方案


下面两个都是柔型数组:


struct S
{
  int n;
  char c;
  int arr[];
};
struct S
{
  int n;
  char c;
  int arr[0];
};

需要注意的是,第二种有的编译器会报错。


柔性数组的特点


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


也就是说,下面这样的写法是绝对不行的:


struct S
{
  int arr[];
};

2.sizeof返回的带有柔型数组的结构体的大小不包括柔型数组。


#include<stdio.h>
struct S
{
  int n;
  char c;
  int arr[];
};
int main()
{
  printf("%d", sizeof(S));
  return 0;
}


2d12ef246e02260f73fb79f3abf38933_9f0d5e82492c416e945bd5a7856ae451.png


我们已经了解了最大对齐数,n和c一共是5字节,但是结构体大小必须是最大对齐数的整数倍,int的对齐数是4,char的对齐数是1,所以浪费三个字节,结构体大小为8,柔型数组的大小并没有被计算在里面。


3.包含柔型数组成员的结构用malloc进行内存的分配,并且分配的内存应该大于结构的大小,用来适应柔型数组的预期大小。


#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
struct S
{
  int n;
  char c;
  int arr[0];
};
int main()
{
  struct S* ps = (struct S*)malloc(sizeof(struct S) + sizeof(int) * 10);
  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;
  printf("%d ", ps->arr[i]);
  }
  struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));
  if (ptr == NULL)
  {
  printf("%s\n", strerror(errno));
  return 1;
  }
  else
  {
  ps = ptr;
  }
  free(ps);
  ps = NULL;
  return 0;
}

柔性数组的柔性就体现在这里,如果我们将结构体中的数组大小定义成一个常量,那么它在一次程序的运行中是不可修改的,但是如果我们用柔性数组来定义的话,就可以动态地用realloc来修改。


需要注意的是,realloc的后一个参数不是要扩容的大小,而是算上本来就有的空间之后的新大小,这一点比较容易搞混。


结构中指针方案


我们也可以这样模拟实现


#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
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]);
  }
    ptr = (int*)realloc(ps->arr, sizeof(int) * 20);
  if (ptr == NULL)
  {
  perror("realloc");
  return 1;
  }
  else
  {
  ps->arr = ptr;
  }
  free(ps->arr);
  ps -> arr = NULL;
  free(ps);
  ps = NULL;
  return 0;
}


这种写法可以模拟实现上面柔型数组的功能,我们称它为结构中指针方案。


那么结构中指针和柔型数组这两个方案到底哪一个比较好呢?


两种方案那个比较好?


如果我们用柔型数组的话,程序里面总共malloc一次,free一次。


如果用结构中指针的话,则是malloc两次,free两次。


这两个方案可以完成同样的功能,但是柔型数组的实现方式有两个好处:


第一个好处是:内存的使用率会高一些


malloc次数少,内存之间的内存碎片就会少一些,内存的使用率就会相应高一些。malloc次数多,维护难度增大,容易出错。


第二个好处是:访问速度会提高


柔型数组是一片连续的空间,访问速度理所应当地会快一些,而结构中指针空间之间可能不连续,我们在访问内存的时候,可能不是直接去内存里面拿,而是先去寄存器里找,寄存器没有再找内存要,如果空间连续,后面空间的内容可能会加载到寄存器里面,那么访问速度就会加快,而如果空间不连续,先去寄存器找却没找到,这么一来效率就会降低。


这篇博客旨在总结我自己阶段性的学习,要是能帮助到大家,那可真是三生有幸!😀如果觉得我写的不错的话还请点个赞和关注哦~我会持续输出编程的知识的!🌞🌞🌞  


相关文章
|
Web App开发 JavaScript 前端开发
从零开始,轻松打造个人化Chrome浏览器插件
从零开始,轻松打造个人化Chrome浏览器插件
380 0
|
4月前
|
人工智能 搜索推荐 数据挖掘
抖音电商API直播间弹幕互动,用户参与度翻倍!
在数字化电商时代,抖音电商API助力商家提升直播互动。通过实时弹幕处理、智能回复与数据分析,实现用户参与度翻倍,增强粘性、提升转化。本文详解API集成步骤与实战应用,助您打造高效直播间。
563 0
|
边缘计算 Ubuntu 安全
CentOS的完美替代品
CentOS的完美替代品
2511 0
|
新零售 人工智能 自然语言处理
北京天源迪科获阿里云首批“铂金合作伙伴”授牌
授牌仪式上, 赵杰辉、王晶昱肯定了自2013年以来,北京天源迪科与阿里云在云计算市场开展的卓有成效的合作,双方在电信运营商、交通、能源、航空等行业都已经积累起了相当成熟的案例。阿里云首选北京天源迪科作为“阿里云企业服务合作伙伴计划”和“Apsara Aliware合作计划”的“铂金合作伙伴”,正是基于双方五年来优势互补、诚信互助、互惠共赢的结果。
5413 0
|
9天前
|
云安全 监控 安全
|
14天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
1493 8
|
7天前
|
人工智能 安全 前端开发
AgentScope Java v1.0 发布,让 Java 开发者轻松构建企业级 Agentic 应用
AgentScope 重磅发布 Java 版本,拥抱企业开发主流技术栈。
498 12