C语言定长数组 变长数组 柔性数组

news2024/11/18 3:37:42

C语言定长数组 变长数组 柔性数组

文章目录

  • C语言定长数组 变长数组 柔性数组
    • 1. 定长数组
    • 2. 变长数组
    • 3. 柔性数组
      • 3.1 结构体的大小
      • 3.2 柔性数组的使用

1. 定长数组

在C99标准之前,C语言在创建数组的时候,数组的大小只能使用常量常量表达式来,或者在初始化数组时,省略数组的大小,这就是所谓的定长数组

#include <stdio.h>
int main()
{
	int arr1[10];
	int arr2[10 + 5];
	int arr3[] = {1,2,3,4,5,6,7,8,9,10};
	return 0;
}

2. 变长数组

有定长数组这样的语法限制,让我们创建数组不够灵活,有时数组大小给大了浪费空间,有时数组大小给小了不够用,所以在C99标准之后,有个一个变⻓数组(variable-length array,简称 VLA)的概念,允许我们在创建数组的时候使用变量

int n = a + b;
int arr[n];

在上述示例中,arr 就是变长数组,因为它的长度取决于变量n的值,编译器没法事先确定,只有运行时才能知道变量n是多少

变长数组特点:

  1. 变长数组⻓度只有运⾏时才能确定,所以变⻓数组不能初始化
  2. 变⻓数组的意思是数组的⼤⼩是可以使⽤变量来指定的,在程序运⾏的时候,根据变量的⼤⼩来指定数组的元素个数,⽽不是说数组的⼤⼩是可变的。数组的⼤⼩⼀旦确定就不能再变化了。

在VS2022中是不支持变长数组的,没法测试,在gcc编译器上可以测试

#include <stdio.h>
int main()
{
 int n = 0;
 scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
 int arr[n];
 int i = 0;
 for (i = 0; i < n; i++)
 {
 scanf("%d", &arr[i]);
 }
 for (i = 0; i < n; i++)
 {
 printf("%d ", arr[i]);
 }
 return 0;
}

在这里插入图片描述

3. 柔性数组

那么有没有一种数组,在确定确定数组的大小,还可以根据需要扩大数组
在C99 中,结构体中的最后⼀个元素允许是未知⼤⼩的数组,这就叫做『柔性数组』成员。
例如:

struct S
{
	int i;
	char c;
	int arr[];
};

在上述示例中,arr就是变长数组

变长数组的特点:

  1. 在结构体中
  2. 最后一个成员
  3. 未知大小的数组

这样的数组就是柔性数组

3.1 结构体的大小

struct S
{
	int i;
	char c;
	int arr[];
};

#include <stdio.h>
int main()
{
	printf("%zd\n", sizeof(struct S));
	return 0;
}

代码运行结果:>8
根据结构体对齐规则,int 4个字节,char 1个字节,总共5个字节,不为最大对齐数4的倍数,对齐至8字节

在存在柔性数组的结构体中,计算结构体的大小时,不会计算柔性数组的大小

3.2 柔性数组的使用

柔性数组是通过 malloc realloc的方式来实现数组大小的扩大的

代码一:

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

struct S
{
	int i;
	char c;
	int arr[];
};
int main()
{
	struct S* p = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int)); //通过结构体指针来访问结构体,开辟一个结构体大小 + 想要开辟数组大小的空间
	if (p == NULL)  //判断开辟是否成功
	{
		perror("malloc fail");
		return 1;
	}
	//使用柔性数组
	int i = 0;  
	for (i = 0; i < 10; i++) 
	{
		p->arr[i] = i;
	}
	struct S* tmp = (struct S*)realloc(p, sizeof(struct S) + 15 * sizeof(int)); //调整数组大小
	if (tmp != NULL)  //判断是否调整成功
	{
		p = tmp;
	}
	else
	{
		perror("realoc fail");
		return 1;
	}
	//使用
	for (i = 10; i < 15; i++)
	{
		p->arr[i] = i;
	}
	//打印
	for (i = 0; i < 15; i++)
	{
		printf("%d ", p->arr[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

看不懂的可以去看看动态内存管理malloc calloc realloc free这篇博客

代码二:

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

struct S
{
	int i;
	char c;
	int *arr;
};
int main()
{
	struct S* p = (struct S*)malloc(sizeof(struct S));  //开辟一块空间给结构体
	if (p == NULL)  //判断开辟是否成功
	{
		perror("malloc fail");
		return 1;
	}
	p->arr = (int*)malloc(10 * sizeof(int));  //开辟数组
	if (p->arr == NULL)  //判断开辟是否成功
	{
		perror("malloc fail");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p->arr[i] = i;
	}
	int* tmp = (int*)realloc(p->arr,15 * sizeof(int)); //调整结构体大小
	if (tmp != NULL) //判断
	{
		p->arr = tmp;
	}
	else
	{
		perror("realoc fail");
		return 1;
	}
	//使用
	for (i = 10; i < 15; i++)
	{
		p->arr[i] = i;
	}
	//打印
	for (i = 0; i < 15; i++)
	{
		printf("%d ", p->arr[i]);
	}
	//释放
	free(p->arr);
	p->arr = NULL;
	free(p);
	p = NULL;
	return 0;
}

代码一代码二可以使用了柔性数组,但是代码一有两个好处:

  1. ⽅便内存释放
    代码一:
    示意图为连续内存,只是为了区分划分为了几块,红色部分为柔性数组调整大小的部分
    在这里插入图片描述
    代码二:
    示意图为连续内存,只是为了区分划分为了几块,红色部分为柔性数组调整大小的部分
    在这里插入图片描述
    代码一的空间是一次性在堆区上开辟的,而代码二是先开辟结构体的空间,再开辟柔性数组的空间的,而既然是开辟的空间,就需要使用free来释放,否则有可能导致内存泄漏,而代码一只需要一次释放,而代码二中结构体往往知道释放,但是结构体成员也需要释放容易被忽视,所以,如果我们把结构体的内存以及其成员要的内存⼀次性分配好了,并返回给⼀个结构体指针,做⼀次free就可以把所有的内存也给释放掉

2.这样有利于访问速度
代码一中是一块连续的内存,连续的内存有益于提⾼访问速度,也有益于减少内存碎⽚。(只是相较于代码二速度会快一点,其实,我个⼈觉得也没多⾼了,反正你跑不了要⽤做偏移量的加法来寻址)

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

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

相关文章

CPU的三大调度

计算机系统中的调度可以分为不同层次&#xff0c;包括作业调度、内存调度和进程调度。这三种调度分别负责管理和优化计算机系统中不同层次的资源分配和执行顺序。 高级调度&#xff1a;作业调度&#xff08;Job Scheduling&#xff09;&#xff1a; 作业调度是指对提交到计算…

国产Type-C PD芯片—接口快充取电芯片

常用USB PDTYPE-C受电端&#xff0c;即设备端协议IC芯片&#xff08;PD Sink&#xff0c;也叫PD诱骗芯片&#xff09;&#xff0c;诱导取电芯片。 产品介绍 LDR6328: ◇ 采用 SOP-8 封装 ◇ 兼容 USB PD 3.0 规范&#xff0c;支持 USB PD 2.0 ◇ 兼容 QC 3.0 规范&#x…

Python绘制多分类ROC曲线

目录 1 数据集介绍 1.1 数据集简介 1.2 数据预处理 2随机森林分类 2.1 数据加载 2.2 参数寻优 2.3 模型训练与评估 3 绘制十分类ROC曲线 第一步&#xff0c;计算每个分类的预测结果概率 第二步&#xff0c;画图数据准备 第三步&#xff0c;绘制十分类ROC曲线 1 数据集…

TailwindCSS 如何设置 placeholder 的样式

前言 placeholder 在前端多用于 input、textarea 等任何输入或者文本区域的标签&#xff0c;它用户在用户输入内容之前显示一些提示。浏览器自带的 placeholder 样式可能不符合设计规范&#xff0c;此时就需要通过 css 进行样式美化。 当项目中使用 TailwindCSS 处理样式时&a…

手把手教你使用axure9画出图书出借的功能界面(原型模型)从0实现图书借阅界面

问题 设计图书出借的功能界面&#xff0c;并使用axure画出界面原型&#xff08;pc端或移动端都可以&#xff09;。就你的设计&#xff0c;你觉得有哪些方面需要跟用户沟通确认&#xff1f; 一、登录界面 1.先将图片背景改成灰色 2.插入文本框 3.插入文字&#xff0c;输入图书…

物联网第十四周总结

本周任务 消息转换器 PostgreSQL学习&#xff0c;JetLinks配置PostgreSQL 问题与总结 JetLinks配置PostgreSQL的时候&#xff0c;启动报错 2023-12-08 09:34:30.478 ERROR 19028 --- [actor-tcp-nio-1] o.h.e.r.e.r.r.R2dbcReactiveSqlExecutor : > Error: c…

Elasticsearch 8.9 refresh刷Es缓冲区的数据到Lucene,更新segemnt,使数据可见

一、相关API的handler1、接受HTTP请求的hander(RestRefreshAction)2、往数据节点发送刷新请求的action(TransportRefreshAction)3、数据节点接收主节点refresh传输的action(TransportShardRefreshAction) 二、在IndexShard执行refresh操作1、根据入参决定是使用lucene提供的阻塞…

Http请求(bug)——路径变量传参遇到特殊符号的问题 URL中的#,?,符号作用

前言 本篇博客分析路径变量传参遇到特殊符号的问题&#xff0c;阐述了URL中的#&#xff0c;&#xff1f;&#xff0c;&符号作用。 目录 前言引出路径变量传参遇到特殊符号的问题问题描述问题分析 URL中的 #&#xff0c;&#xff1f;&#xff0c;&符号的作用URL中# 的作…

【探索Linux】—— 强大的命令行工具 P.21(多线程 | 线程同步 | 条件变量 | 线程安全)

阅读导航 引言一、线程同步1. 竞态条件的概念2. 线程同步的概念 二、条件变量1. 条件变量函数⭕使用前提&#xff08;1&#xff09;初始化条件变量&#xff08;2&#xff09;等待条件满足&#xff08;3&#xff09;唤醒等待pthread_cond_broadcast()pthread_cond_signal() &…

Qexo博客后台管理部署

Qexo博客后台管理部署 个人主页 个人博客 参考文档 https://www.oplog.cn/qexo/本地部署 采用本地Docker部署管理本地Hexo 下载代码包 若无法下载使用科学工具下载到本地在上传到服务器 wget https://github.com/Qexo/Qexo/archive/refs/tags/3.0.1.zip# 解压 unzip Qexo…

SQL命令---修改字段的排列位置

介绍 使用sql语句表字段的排列顺序。 命令 alter table 表名 modify 字段名1 数据类型 first|after 字段名2;例子 将a表中的age字段改为表的第一个字段。 alter table a modify age int(12) first;下面是执行命令后的表结构&#xff1a; 将a表中的age字段放到name字段之…

【linux】查看CPU和内存信息

之前咱们一起学习了查看内存的和CPU的命令。 ​mpstat &#xff1a; 【linux】 mpstat 使用 uptime&#xff1a;【Linux】 uptime命令使用 CPU的使用率&#xff1a;【linux】查看CPU的使用率 nmon &#xff1a;【linux】nmon 工具使用 htop &#xff1a;【linux】htop 命令…

学习Linux(2)-学习Linux命令

Linux目录结构 Linux目录结构-菜鸟教程 /bin&#xff1a;bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。 /boot&#xff1a;这里存放的是启动 Linux 时使用的一些核心文件&#xff0c;包括一些连接文件以及镜像文件。 /dev &#xff1a;dev 是 De…

Cocos Creator:创建棋盘

Cocos Creator&#xff1a;创建棋盘 创建地图三部曲&#xff1a;1. 创建layout组件2. 创建预制体Prefab&#xff0c;做好精灵贴图&#xff1a;3. 创建脚本LayoutSprite.ts收尾工作&#xff1a; 创建地图三部曲&#xff1a; 1. 创建layout组件 使用layout进行布局&#xff0c;…

数据表记录的操作

一、数据添加 1、打开SSMS&#xff0c;附加数据库&#xff08;数据库文件在自己的文件夹下面&#xff09;&#xff0c;并进行下面的设置&#xff1a; &#xff08;1&#xff09;设置“部门信息”表中的“编号”为主键&#xff08;SSMS&#xff09; 首先建立好所需的数据库库…

HNU计算机视觉作业三

前言 选修的是蔡mj老师的计算机视觉&#xff0c;上课还是不错的&#xff0c;但是OpenCV可能需要自己学才能完整把作业写出来。由于没有认真学&#xff0c;这门课最后混了80多分&#xff0c;所以下面作业解题过程均为自己写的&#xff0c;并不是标准答案&#xff0c;仅供参考 …

单臂路由与三层交换机

单臂路由 划分VLAN后同一VLAN的计算机属于同一个广播域&#xff0c;同一VLAN的计算机之间的通信是不成问题的。然而&#xff0c;处于不同VLAN的计算机即使是在同一交换机上&#xff0c;它们之间的通信也必须使用路由器。 图&#xff08;a&#xff09;是一种实现VLAN间路由的方…

ubuntu上搭建bazel编译环境,构建Android APP

背景是github上下载的工程&#xff0c;说明仅支持bazel编译&#xff0c;折腾了一天Android studio&#xff0c;失败。 不得不尝试单价bazel编译环境&#xff0c;并不复杂&#xff0c;过程记录如下 说明&#xff1a;ubuntu环境是20.04&#xff0c;pve虚拟机安装 1.安装jdk sudo…

docker-compose安装教程

1.确认docker-compose是否安装 docker-compose -v如上图所示表示未安装&#xff0c;需要安装。 如上图所示表示已经安装&#xff0c;不需要再安装&#xff0c;如果觉得版本低想升级&#xff0c;也可以继续安装。 2.离线安装 下载docker-compose安装包&#xff0c;上传到服务…

如何将html网页免费转为excel?

一、直接复制。 直接复制是最简单有效、快捷的解决方案&#xff0c;操作方法如下&#xff1a; 1、用鼠标像平常复制文本一样&#xff0c;将整个网页表格选中。 2、点击右键&#xff0c;点击“复制”。 3、打开excel软件&#xff0c;鼠标点击任意单元格。 4、点击右键&#…