动态内存分配(3)——柔性数组

news2024/11/25 6:41:59

前言:

        以前我们所学数组(包括变长数组),在数组声明的时候,就必须指定数组的大小,它所需要的内存在编译时分配。但是有时候需要的数组大小在程序运行的时候才能知道,该怎么办呢?这就是我们今天要来学习的新内容——柔性数组。

目录:

        一、柔性数组介绍

        二、柔性数组的特点

        三、柔性数组的使用

        四、柔性数组的优势


一、柔性数组的介绍

        柔性数组(flexible array):在C99中,结构的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。

示例:

typedef struct st_type
{
	int i;
	int a[0];//表示数组的大小是未知的——柔性数组成员
}type_a;

有些编译器会报错无法编译可以改成将a[0]改为a[]:

typedef struct st_type
{
	int i;
	int a[];//表示数组的大小是未知的——柔性数组成员
}type_a;

注意:

        1、柔性数组是C99中引入的,支持C99柔性数组的编译器才可使用柔性数组(VS集成开发支持)。

        2、柔性数组成员必须是结构体的成员,还必须是结构中的最后一个成员。

        3、柔性数组成员在声明的时候数组大小不写和数组大小为0是一样的(arr[]和arr[0]),表示数组的大小是未知的。

二、柔性数组的特点

特点:

        1、结构中的柔性数组成员前面必须至少有一个其他成员(我们想分配一个不定长的数组,所以定义一个结构体,最少有两个成员。一个代表数组的长度,一个是柔性数组成员)。

        2、sizeof返回的这种结构大小不包括柔性数组的内存(零长度的数组存在于结构体中,但是不占结构体的大小,可理解为一个没有内容的占位标识,直到我们给结构体分配了内存,这个占位标识才变成一个有长度的数组)。

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

讲解:

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

        代码演示:

​
typedef struct st_type
{
	int i;//必须至少有一个其他成员——数组长度
	int a[];//表示数组的大小是未知的——柔性数组成员
}type_a;

​

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

        代码演示:

#include<stdio.h>

typedef struct S
{
	int i;//必须至少有一个其他成员
	int a[];//表示数组的大小是未知的——柔性数组成员
}S;

int main()
{
	//计算结构体的大小并将其打印
	printf("%d\n", sizeof(S));
	return 0;
}

        运算结果:

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

        代码演示:

#include<stdio.h>
#include<stdlib.h>

typedef struct S
{
	int i;//必须至少有一个其他成员
	int a[];//表示数组的大小是未知的——柔性数组成员
}S;

int main()
{
	//使用柔性数组成员的结构,使用malloc进行内存分配,
	//并且分配的内存应该大于结构的大小。
	//给柔性数组开辟10个整形的空间
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	return 0;
}

         图示:

 

三、柔性数组的使用

        代码演示1:使用柔性数组——结构体中数据是连续的

​
#include<stdio.h>
#include<stdlib.h>

typedef struct S
{
	int i;//必须至少有一个其他成员
	int a[];//表示数组的大小是未知的——柔性数组成员
}S;

int main()
{
	//给柔性数组成员开辟10个整形的空间
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	//判断是否开辟成功
	if (NULL == ps)
	{
		//打印错误信息
		perror("malloc");
		return 1;
	}
	//使用
	ps->i = 10;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->a[i] = i;
		printf("%d ", ps->a[i]);
	}
	//增容,在添加10个整形
	struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));
	if (ptr != NULL)
	{
		ps = ptr;
        ps-> i = 20;
	}
	else
	{
		perror("realloc");
		//增容失败,释放之前开辟的
		free(ps);
		ps = NULL;
		return 1;
	}
	//再次使用(略)
	//释放增容成功
	free(ps);
	ps = NULL;
	return 0;
}

​

四、柔性数组的优势

        代码演示2:不使用柔性数组——结构体中的数据不连续

​
#include<stdio.h>
#include<stdlib.h>

typedef struct S
{
	int i;
	int* a;//不使用int a[]柔性数组,使用指针
}S;

int main()
{
	//给结构S开辟空间
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	//判断是否开辟成功
	if (NULL == ps)
	{
		//打印错误信息
		perror("malloc");
		return 1;
	}
	//使用
	ps->i = 10;
	ps->a = (int*)malloc(10 * sizeof(int));
	if (NULL == ps->a)
	{
		//打印错误信息
		perror("malloc->a");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->a[i] = i;
		printf("%d ", ps->a[i]);
	}
	//增容,在添加10个整形
	int* ptr = (int*)realloc(ps->a, 20 * sizeof(int));
	if (ptr != NULL)
	{
		ps->a = ptr;
        ps->i = 20;
	}
	else
	{
		perror("realloc->ptr");
		//增容失败,先释放结构体指针a指向的之前开辟的空间
		//(因为先释放结构体的空间,就找不着a指向的空间了)
		free(ps->a);
		ps->a = NULL;
		//再释放结构体的空间
		free(ps);
		ps = NULL;
		return 1;
	}
	//再次使用(略)
	//释放增容成功
	//先释放结构体指针a指向的之前开辟的空间
	//(因为先释放结构体的空间,就找不着a指向的空间了)
	free(ps->a);
	ps->a = NULL;
	//再释放结构体的空间
	free(ps);
	ps = NULL;
	return 0;
}

​

        上面代码演示1和代码演示2都可以完成同样的功能,谁更好呢?

        答案是:代码演示1,他有两个好处。

        好处1:方便内存释放

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

        图示:

        好处2:有利于访问速度

        连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,也没多高,因为都要用偏移量的加法来寻址)。

        图示:

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

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

相关文章

Zookeeper+kafka的应用及部署

Zookeeperkafka的应用及部署 一、Zookeeper的概念1、Zookeeper 定义2、Zookeeper 工作机制3、Zookeeper 特点4、Zookeeper 数据结构5、Zookeeper 应用场景6、Zookeeper 选举机制&#xff08;1&#xff09;第一次启动选举机制&#xff08;2&#xff09;非第一次启动选举机制(1)、…

【Ajax】笔记-NodeMon 简介、安装、使用

NodeMon 简介、安装、使用 简介安装启动应用测试 简介 nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。以前&#xff0c;我们开发一个node后端服务时&#xff0c;每次更改文件&#xff0c;均需重启一下&#xff0c;服务才能生效。这使我们…

阿里云RocketMQ——高可用、高可靠的分布式消息处理系统

阿里云产品测评-RocketMQ 今天我对阿里的又一产品进行了深度测评&#xff08;RocketMQ&#xff09;&#xff0c;首先如果是新用户的话&#xff0c;可以先关注下面这个免费体验的活动。 一、上手实操 阿里云免费试用 1.付费或者免费开通RocketMQ 云消息队列 RocketMQ 版是阿…

容器云平台监控告警体系(四)—— Golang应用接入Prometheus

1、概述 目前容器云平台中的容器仅支持获取CPU使用率、内存使用率、网络流入速率和网络流出速率这4个指标&#xff0c;如果想监控应用程序的性能指标或者想更加细粒度的监控应用程序的运行状态指标的话&#xff0c;则需要在应用程序中内置对Prometheus的支持或者部署独立于应用…

悦数图数据库v3.5.0发布:查询性能大幅提升,为智能决策和 AI 大模型应用提速

近日&#xff0c;悦数图数据库最新版本&#xff08;v3.5.0&#xff09;正式发布&#xff0c;作为国内首个能够容纳千亿点、万亿边并保持毫秒级查询延时的企业级原生分布式图数据库&#xff0c;悦数图数据库 3.5.0 版本进一步强化了数据库内核的查询性能和稳定性&#xff0c;同时…

socks协议详解

0x01 socks协议简介 Socks&#xff08;Socket Secure&#xff09;协议是一种网络协议&#xff0c;处于会话层&#xff0c;用于管理网络连接并提供安全性和隐私保护。通过使用Socks代理服务器&#xff0c;客户端可以隐藏其真实IP地址和其他身份信息&#xff0c;从而匿名地访问互…

机器学习 day28(模型评估)

为什么需要模型评估 我们可以借助图像来判断模型是否良好。但当我们用单一特征来绘制f(x)图像时&#xff0c;模型容易出现过拟合现象。但如果增加一些输入特征的种类&#xff0c;绘制图像又会变得很困难。而模型评估可以解决这一痛点。 模型评估 通常我们将数据集的一大半…

[C语言]if语句详解

C语言初阶系列 分支语句和循环语句&#xff08;1&#xff09; 目录 C语言初阶系列 前言 一&#xff0c;什么是语句&#xff1f; 1.1如何理解语句&#xff1f; 二&#xff0c;分支语句&#xff08;选择结构&#xff09; 2.1,if语句 2.2,if语句的错误的条件写法 2.2,if语…

Houdini Vex 补缺

一. transorm —— move—— scale—— rot1.这里 补2 个函数 quaternion( ) &#xff08;角度&#xff08;弧度制&#xff09;, 轴&#xff09; 获取4元数 qroate( ) &#xff08;quaternion &#xff0c;点坐标&#xff09; 进行旋转 案例&#xff1a; 参考 视频连接 般 b站…

【山河送书第三期】:《Python机器学习:基于PyTorch和Scikit-Learn 》赠书四本!!

【山河送书第三期】&#xff1a;《Python机器学习&#xff1a;基于PyTorch和Scikit-Learn 》 前言内容简介作者简介参与方式 前言 近年来&#xff0c;机器学习方法凭借其理解海量数据和自主决策的能力&#xff0c;已在医疗保健、 机器人、生物学、物理学、大众消费和互联网服务…

如何向资深开发人员寻求帮助(并获得帮助)

在程序开发过程中&#xff0c;我们时常会遇到让人挠头的问题。如何寻求帮助&#xff0c;尤其是如何向资深开发人员寻求帮助&#xff0c;是一门值得学习的技艺。这并不只是简单地把问题抛出来&#xff0c;而是需要学会在何时求助&#xff0c;如何提问&#xff0c;如何理解答案&a…

股票量化系统QTYX选股框架实战案例集|越强的龙头出分歧,越大可能出反包-230717...

前言 “实战案例个股画像”系列和大家分享我基于QTYX选股框架&#xff0c;在实战中选股的案例&#xff0c;和大家一起见证QTYX选股框架逐步完善的过程&#xff0c;帮助大家理解QTYX的精髓。 关于QTYX的使用攻略可以查看链接&#xff1a;QTYX使用攻略 关于QTYX初衷和精髓可以查看…

怎么用Midjourney制作表情包

要使用Midjourney制作表情包&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 打开Midjourney的官方网站或下载Midjourney应用程序&#xff0c;并登录你的账户。 2. 在Midjourney中&#xff0c;选择创建新项目或表情包。 3. 在项目中&#xff0c;你可以选择使用预设的模…

【学习笔记】浅谈最小生成树及重构树

板子传送门 定义 生成树 一个连通图的生成树是一个极小的连通子图&#xff0c;它包含图中全部的 n n n 个顶点&#xff0c;但只有构成一棵树的 n − 1 n-1 n−1 条边。 最小生成树 其实就是一个图中最小的一个生成树 所谓一个 带权图 的最小生成树&#xff0c;就是原图中…

Label基本用法

作用&#xff1a;是一个标签&#xff0c;可以用来显示文本&#xff1b; 常用属性&#xff1a; 常用事件&#xff1a; 后台代码示范&#xff1a; //d单击标签时触发private void label1_Click(object sender, EventArgs e){MessageBox.Show("标签被单击");//获取标签…

Python(十九)python中的注释

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

优化算法之梯度下降|Matlab实现梯度下降算法

题目要求&#xff1a; 使用Matab实现梯度下降法 对于函数&#xff1a; min ⁡ f ( x ) 2 x 1 2 4 x 2 2 − 6 x 1 − 2 x 1 x 2 \min f(x)2 x_{1}^{2}4 x_{2}^{2}-6 x_{1}-2 x_{1} x_{2} minf(x)2x12​4x22​−6x1​−2x1​x2​ 试采用 MATLAB实现最速下降法求解该问题, 给…

深度学习路线

深度学习路线 机器学习视频 吴恩达 http://open.163.com/special/opencourse/machinelearning.html 神经网络深度学习在线教程 共六章 http://neuralnetworksanddeeplearning.com 《神经网络设计》 国外经典教程 第十一章 反向传播 CNN:《Notes On Convolutional Neutral Netw…

h5live 2.0.1 合入测试

直接超过1个G 有消息进来&#xff0c;就是不显示

SpringBoot 整合 RabbitMQ demo

Rabbit Windows安装教程 本文只做Demo案例的分享&#xff0c;具体只是需自行百度 一、生产者 1.application.properties 配置Rabbit的基本信息 #rabbit 主机IP spring.rabbitmq.host127.0.0.1 #rabbit 端口 spring.rabbitmq.port5672 #rabbit 账号 可自行创建 这里是默认的 …