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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

后端只打印了info等级的日志?-SpringBoot日志打印-Slf4j

在调用log变量的方法来输出日志时&#xff0c;有以上5个级别对应的方法&#xff0c;从不太重要&#xff0c;到非常重要 调用不同的方法&#xff0c;就会输出不同级别的日志。 trace&#xff1a;跟踪信息debug&#xff1a;调试信息info&#xff1a;一般信息warn&#xff1a;警告…

一个最小的物联网系统设计方案及源码(一)——系统组成

关于物联网 物联网&#xff08;Internet of Things&#xff0c;缩写IOT&#xff09;是一个基于互联网、传统电信网等信息承载体&#xff0c;让所有能够被独立寻址的普通物理对象实现互联互通的网络。 物联网一般为无线网&#xff0c;由于每个人周围的设备可以达到一千至五千个&…

css选择器介绍

css选择器介绍 01 css概念介绍 用于更改标签的视觉效果 02 css格式 选择器 {属性1&#xff1a;值1&#xff1b;属性2&#xff1a;值2} 03 三种样式 1.内联样式 直接写在标签的style属性中。 优点&#xff1a;简单明显缺点&#xff1a;无法重复使用代码 <img src&quo…

【Pandas】时间序列数据按年聚合

想做什么 有一个时间序列数据&#xff0c;希望按财政年度而不只是按年对其进行汇总。 例如以下“账单信息”&#xff0c;并希望按财政年度对其进行总计。 import pandas as pd# 样本数据 data {计费月份: [2020-02-01, 2020-05-01, 2021-02-01, 2021-04-01],计费ID: [1, 2,…

MongoDB表的主键可以重复?!MongoDB的坑

MongoDB表的主键可以重复&#xff1f;&#xff01; 眼见为实&#xff1f; 碰到一个奇怪的现象&#xff0c; MongoDB的一个表居然有两个一样的_id值&#xff01; 再次提交时&#xff0c;是会报主键冲突的。那上图&#xff0c;为什么会有两个一样的_id呢&#xff1f; 将它们的…

Redis - 事务隔离机制

Redis 的事务的本质是 一组命令的批处理 。这组命令在执行过程中会被顺序地、一次性 全部执行完毕&#xff0c;只要没有出现语法错误&#xff0c;这组命令在执行期间是不会被中断。 当事务中的命令出现语法错误时&#xff0c;整个事务在 exec 执行时会被取消。 如果事务中的…

Linux中的堡垒机搭建以及使用

JumpServer搭建 安装应用包 curl -sSL https://resource.fit2cloud.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash 一路回车即可安装完毕&#xff08;可根据需求更改&#xff09; JumpServer的 配置文件路径 /opt/jumpserver/config/config.tx…

数字人er-nerf安装

目录 服务器环境 环境准备 1.下载源码 2.安装Ancoda环境 3.安装cudatoolkit 4.安装cuDNN 5.安装pytorch 6.安装requirements 7.安装tensorflow 8.安装pytorch3d 9.gcc安装 训练准备 训练 1.处理视屏 2.准备眨眼数据 3.头部训练 4.嘴唇 5.身体 6.生成推理音频…

利用transition-group标签包裹li标签,实现输入数据后按Enter键将数据添加到列表中

1.效果图 2.代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title></title><script src"https://cdn.bootcdn.net/ajax/libs/vue/2.3.0/vue.js"></script><div id&quo…

LangChain学习二:提示-实战(下半部分)

文章目录 上一节内容&#xff1a;LangChain学习二&#xff1a;提示-实战&#xff08;上半部分&#xff09;学习目标&#xff1a;提示词中的示例选择器和输出解释器学习内容一&#xff1a;示例选择器1.1 LangChain自定义示例选择器1.2 实现自定义示例选择器1.2.1实战&#xff1a…

EMT(light sr):Efficient Mixed Transformer for Single Image Super-Resolution

EMT 论文地址&#xff1a;Efficient Mixed Transformer for Single Image Super-Resolution 代码地址&#xff1a;Fried-Rice-Lab/EMT: Efficient Mixed Transformer for Single Image Super-Resolution (github.com) 摘要 ​ 最近&#xff0c;基于 Transformer 的方法在单…

Unity 修改游戏对象的旋转角度Rotation的方法

在Unity中要修改游戏对象中的旋转角度&#xff0c;即下图中的Rotation: 有三个方法&#xff1a; 1、 使用欧拉角&#xff08;Euler Angles&#xff09;&#xff1a;欧拉角是一组表示旋转的三个角度值&#xff08;绕X轴的旋转、绕Y轴的旋转和绕Z轴的旋转&#xff09;。 transf…

word中表格跨页

有时候在word中输入内容后&#xff0c;出现断开情况&#xff0c;如下图 处理的方法是&#xff0c;选中表格&#xff0c;右击选项&#xff0c;在行--允许跨页断行勾选即可

妙手ERP特色功能来袭:上线Lazada包邮营销功能,全方位助力卖家高效引流!

包邮是线上消费者作出购买决策的重要因素&#xff0c;据Lazada平台调研显示&#xff1a;73%的受访者希望商品免费配送&#xff0c;有84%的消费者使用过Lazada包邮优惠券&#xff0c;其中75%的消费者对此感到满意。由此可见&#xff0c;包邮已成为打动东南亚消费者下单的主要原因…

【教程】如何将重要文件进行混淆和加密

怎么保护苹果手机移动应用程序ipa中文件安全&#xff1f; ios应用程序存储一些图片&#xff0c;资源&#xff0c;配置信息&#xff0c;甚至敏感数据如用户信息、证书、私钥等。这些数据怎么保护呢&#xff1f;可以使用iOS提供的Keychain来保护敏感数据&#xff0c;也可以使用加…

智选假日酒店大中华区迎来开业、在建500家里程碑

“90后”先锋品牌&#xff0c;智选假日酒店在华实现骄人突破&#xff0c;成就非凡 2023年12月12日&#xff0c;中国上海 — 洲际酒店集团今日宣布&#xff0c;旗下中高端精选服务品牌智选假日酒店迎来大中华区的开业和在建酒店数量突破500家这一发展里程碑。智选假日酒店凭借其…

深入理解Java关键字volatile

前置知识-了解以下CPU结构 如下图所示&#xff0c;每个CPU都会有自己的一二级缓存&#xff0c;其中一级缓存分为数据缓存和指令缓存&#xff0c;这些缓存的数据都是从内存中读取的&#xff0c;而且每次都会加载一个cache line&#xff0c;关于cache line的大小可以使用命令cat…

Oracle(2-17) RMAN Maintenance

文章目录 一、基础知识1、Retention Policy 保留政策2、Recovery Window - Part 1 恢复窗口-第1部分3、Cross Checking 交叉检查4、The CROSSCHECK Command CROSSCHECK命令5、OBSOLETE VS EXPIRED 过时与过期6、Deleting Backups and Copies 删除备份和副本7、The DELETE Comma…

如何使用内网穿透实现iStoreOS软路由R4S公网远程访问局域网电脑桌面

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 简介一、配置远程桌面公网地址二、家中使用永久固定地址…