梦开始的地方——C语言柔性数组

news2024/10/7 10:21:01

文章目录

  • 柔性数组
    • 什么是柔性数组?
    • 柔性数组的使用
    • 柔性数组的优点


柔性数组

什么是柔性数组?

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

这个概念听起来可能有点不可以思议,但它的确存在。

来看这么一段代码

struct Test
{
	int num;
	int arr[0];//柔性数组成员
};

上面那个写法有的编译器可能会报错,可以改成以下写法。

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

这里的arr数组就是一个柔性数组,它没有指定数组的大小,arr[0]这样的写法也非常奇怪。但这种写法只限于结构体的最后一个成员。柔性数组指的是数组的大小是柔性可变的。

柔性数组的使用

来看一段代码

#include <stdio.h>
#include <stdlib.h>
typedef struct Test
{
	int num;
	int arr[0];
}Test;
int main()
{
	printf("%d\n", sizeof(Test));

	return 0;
}

打印结果

4

计算这个结构体大小,发现这个数组是不占用任何空间的。那么柔性数组到底如何使用呢?

错误写法

struct Test t;//这样创建时错误的

正确的创建方法

Test* t = (Test*)malloc(sizeof(Test) + 10 * sizeof(int));

通过malloc函数给这个结构体和柔性数组开辟了空间,就可以使用这一块空间了

#include <stdio.h>
#include <stdlib.h>
typedef struct Test
{
	int num;
	int arr[0];
}Test;
int main()
{
	Test* t = (Test*)malloc(sizeof(Test) + 10 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		t->arr[i] = 100;
	}


	return 0;
}

此时的内存布局

在这里插入图片描述

我们发现通过malloc函数给结构体开辟空间,就可以给柔性数组开辟空间。而这一块空间既然是用malloc函数开辟的,那么它就可以通过realloc函数来调整大小。这不就体现出了柔性数组的作用了吗?

那么使用柔性数组有哪些注意事项呢?

  1. 结构体中的柔性数组成员前面至少要定义一个成员变量

    柔性数组前至少要有一个成员变量,才是合法的。

    typedef struct Test
    {
        int num;//前面至少要包含一个成员变量
    	int arr[];
    }Test;
    
  2. **sizeof 返回的这种结构大小不包括柔性数组的内存 **

    这个前面已经演示过了,sizeof函数计算的结构体大小是不包含柔性数组大小的

  3. 包含柔性数组成员的结构用malloc函数进行内存的动态分配,分配的内存要大于结构体的大小

    比如下面这个代码,分配了结构体大小在加上40个字节的连续空间,那么柔性数组就能存储10个整形元素。

    sizeof(Test)开辟的空间是给num成员变量使用的,而后面的空间则是在给柔性数组使用的。

    #include <stdio.h>
    #include <stdlib.h>
    typedef struct Test
    {
        int num;
    	int arr[];
    }Test;
    int main()
    {
    	Test* t = (Test*)malloc(sizeof(Test) + 10 * sizeof(int));
    	return 0;
    }
    

柔性数组的优点

提到动态扩容,不是指针也能做到吗?为什么还要有柔性数组这个玩样呢?

柔性数组动态扩容和指针动态扩容对比

#include <stdio.h>
#include <stdlib.h>
typedef struct S1
{
	int num;
	int* pArr;//指针
}S1;
typedef struct S2
{
	int num;
	int arr[0];//柔性数组成员
}S2;
int main()
{
	//指针开辟
	S1* ps1 = (S1*)malloc(sizeof(S1));
	ps1->pArr = (int*)malloc(sizeof(int)*10);
	//柔性数组开辟
	S2* ps2 = (S2*)malloc(sizeof(S2) + sizeof(int) * 10);

	//指针扩容
	int* ptr1 = (int*)realloc(ps1->pArr,sizeof(int) * 20);
	if (ptr1 != NULL)
	{
		ps1->pArr = ptr1;
		ptr1 = NULL;
	}
	//柔性数组扩容
	S2* ptr2 = (S2*)realloc(ps2,sizeof(S2) + sizeof(int) * 20);
	if (ptr2 != NULL)
	{
		ps2 = ptr2;
		ptr2 = NULL;
	}
	//指针释放
	free(ps1->pArr);
	free(ps1);
	//柔性数组释放
	free(ps2);

	return 0;
}

指针开辟和柔性数组都能达到同样的效果,那么他们有什么不一样呢?

在这里插入图片描述

  1. 方便内存释放,防止内存泄露

    柔性数组只需要一次free就能释放。而使用指针的方式就需要释放两次,假设通过指针的方式的代码是放的一个函数中给别人调用,就可能出现忘记释放指针指向的内存,从而导致内存泄露。

   //需要先释放掉指针的空间
   free(ps1->pArr);
   //再释放结构体
   free(ps1);
  1. 提高内存访问效率,减少内存碎片

    通过柔性数组开辟空间的方式一定是连续的,而通过指针开辟的方式则不一定是连续的。而内存访问连续的空间的效率会更高一点,如果不断的在内存中开辟空间,开辟的内存空间又不连续就会造成大量的内存碎片。导致空间被浪费。

    比如下面的,假设红色的是内存块,那么两个内存块之间的空间比较小,有些人程序想用但太小了,导致无法使用,内存碎片太多就导致了更多内存资源的浪费。但柔性数组开辟的内存空间一定是连续的,所以它可以减少内存碎片的产生。

在这里插入图片描述


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

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

相关文章

KVC原理与数据筛选

作者&#xff1a;宋宏帅 1 前言 在技术论坛中看到一则很有意思的KVC案例&#xff1a; interface Person : NSObject property (nonatomic, copy) NSString *name; property (nonatomic, assign) NSInteger age; end Person *person [Person new]; person.name "Tom&q…

[附源码]计算机毕业设计springboot基于JavaWeb的学校社团活动管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

小知识· Zigbee 简介

1. 介绍 ZigBee是一种近距离、低复杂度、低功耗、低速率、低成本的双向无线通讯技术 ZigBee建立在IEEE 802.15.4标准&#xff08;定义了PHY和MAC层&#xff09;之上&#xff0c;ZigBee联盟对其网络层和应用层进行了标准化 ZigBee协议栈可分为五层 - 物理层&#xff08;PHY&a…

时间序列建模三部曲

与大多数高级分析解决方案不同&#xff0c;时间序列建模是一种低成本解决方案&#xff0c;可提供强大的洞察力。 本文将介绍构建质量时间序列模型的三个基本步骤&#xff1a;使数据平稳&#xff0c;选择正确的模型并评估模型的准确性。这篇文章中的例子使用了一家主要汽车营销…

[附源码]Python计算机毕业设计SSM旅行网的设计与实现(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

从零搭建开发脚手架 注意Logback多个配置文档导致配置紊乱问题

文章目录背景查找logback内部状态以及生效的配置文件解决背景 最近项目中出现个问题&#xff0c;自定义的logback.xml不生效&#xff0c;排查发现项目中出现了2个logback.xml&#xff0c;另一个在依赖Jar中&#xff0c;使用的在依赖Jar中的logback.xml&#xff0c;导致我们自定…

Azkaban源码阅读与本地调试

1、架构 2、本地源码加载,gradle会下载依赖。 AzkabanWebServer 配置 参数如下: -Dlog4j.configuration=file:///D:\workspace_com\azkaban\azkaban\azkaban-web-server\src\main\resources\conf\log4j.properties -conf D:\\workspace_com\\azkaban\\azkaban\\azkaban-…

Unity实现摄像头录像功能

Unity实现摄像头录像功能 前言 在之前的很多展馆展示的项目中&#xff0c;甲方有很多要求实现用摄像头录像的功能。使用Unity实现调用USB摄像头画面的功能非常容易实现&#xff0c;但是实现录屏的功能有一些困难&#xff0c;我使用了几种方法都没有实现出想要的效果&#xff…

广播实现强制下线功能

实现强制下线功能 强制下线应该是一个比较常用的功能,比如QQ在比的地方被登陆了,就会强制比被挤下线.强制下线的功能还是比较简单的,只需要在界面上弹出一个框,告知用户无法再进行任何操作即可.只能点击确定然后跳转至登录界面.强制下线功能需要关闭所有的Activity,然后返回到…

5 - 2 单选题

1.下列线索二叉树中&#xff08;用虚线表示线索&#xff09;&#xff0c;符合后序线索树定义的是&#xff1a;B 后序线索二叉树的构建流程就是&#xff1a; 1.后序遍历二叉树&#xff1a;d b c a 2.第一个结点的前驱是NULL&#xff0c;即d的前驱&#xff0c;d的左孩子为NULL …

在 Android 中创建静态应用程序快捷方式

您是否在日常应用程序中看到过快捷方式示例?可能像 Instagram、Discord、Medium 等。提供它们是为了帮助我们快速导航到应用程序内部的特定功能、屏幕或部分,而无需逐步浏览它们。 在本文中,我们将逐步实现静态快捷方式。但在我们开始编码之前,我们需要知道这个快捷方式到底…

大数据(9h)FlinkSQL之Lookup Join

文章目录概述pom.xmlMySQL建表对应Flink的建表SQLLookup JoinFlinkSQL完整Java代码概述 lookup join通常是 查询外部系统的数据 来 充实FlinkSQL的主表 例如&#xff1a;事实表 关联 维度表&#xff0c;维度表在外部系统&#xff08;如MySQL&#xff09;要求&#xff1a; 1个表…

中国多媒体与网络教学学报杂志社中国多媒体与网络教学学报编辑部2022年第9期目录

多媒体信息技术《中国多媒体与网络教学学报》投稿&#xff1a;cn7kantougao163.com 采油工程探索式虚拟仿真实验教学实践——以有杆抽油系统实验为例 窦祥骥 ;何岩峰 ;张少辉 ;王相 ;徐慧 ; 1-5 人体寄生虫课程网络虚拟实验环境的构建及其应用研究 周蕾;贺帅;李晓琳;席…

深入理解mysql执行的底层机制

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解explain以及索引优化https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql事务本质https://blog.cs…

3dmax如何进行网络渲染?网渲云渲染渲染农场怎么用?

渲染本身是将3d模型转换为2d图像的一个过程&#xff0c;而网络渲染就是把3d模型放在云端进行完成&#xff0c;而本地我们只需要等待结果就好。而云渲染也就是网渲的标准称呼&#xff0c;两个是一个意思。 那怎么进行网络渲染呢&#xff1f; 首先我们需要下载网络渲染客户端&a…

03-Docker-Docker镜像的分层概念

目录 一、镜像是什么 二、UnionFS&#xff08;联合文件系统&#xff09; 三、Docker镜像加载原理 四、将容器生成为镜像Commit命令 一、镜像是什么 是一种轻量级、可执行的独立软件包&#xff0c;包含运行某个软件所需的所有内容&#xff0c;我们把应用程序和配置依赖打包好…

TextBox文本框与PasswordBox密码框水印

在开发一个软件和网页的时候&#xff0c;都会有一个功能&#xff0c;那就是登陆功能&#xff0c;有了登陆那就一定需要用户输入账号和密码&#xff0c;我们在写登陆页面都会想到使用TextBox和PasswordBox去完成这两个功能&#xff0c;但是有一个问题&#xff0c;那就是如果你使…

java EE初阶 — 线程的状态

文章目录1.状态的基本认识2.观察线程的所有状态3.线程状态和状态转移4.多线程的意义1.状态的基本认识 NEW 创建了 Thread 对象&#xff0c;但是还没调用 start&#xff08;内核里还没有创建对应的PCB&#xff09;TERMINATED 表示内核中的 PCB 已经执行完毕了&#xff0c;但是 …

zabbix监控触发器与报警动作

目录 一、环境准备 1、搭建zabbix基础环境 2、创建被监控主机 二、触发器概念 三、创建触发器 1、创建触发器步骤 2、触发器表达式 &#xff08;1&#xff09;表达式格式 &#xff08;2&#xff09;表达式函数 3、配置触发器 四、创建报警动作 1、设置邮箱服务器 …

学生选课系统

项目描述 通过项目背景的分析以及了解到现在学校面临的问题&#xff0c;特别需要一个选课管理系统保证学生信息以及各种课程成绩的准确性和实效性&#xff0c;通过利用计算机的高速计算和快速的统计分析&#xff0c;保证学生信息的最新记录。从教职工的角度老考虑&#xff0c;…