柔性数组详解

目录

导读:

[1. 什么是柔性数组](#1. 什么是柔性数组)

[2. 柔性数组的特点](#2. 柔性数组的特点)

[3. 柔性数组的使用](#3. 柔性数组的使用)

[4. 柔性数组与其它对比优势](#4. 柔性数组与其它对比优势)

[5. 内存碎片](#5. 内存碎片)


导读:

有关柔性数组开辟相关的malloc函数博文:

C语言动态内存管理(malloc, calloc,realloc)详解-CSDN博客

结构体以及其大小的计算:

结构体、枚举以及联合类型在内存中的存储与大小计算-CSDN博客

1. 什么是柔性数组

柔性数组也称为变长数组,是一种动态数组的实现方式。

与普通数组不同的是,柔性数组在定义时不需要明确指定数组大小,在程序运行时可以动态地分配和扩展数组大小。

柔性数组是通过C99标准中提供的"结构体成员为未知长度的数组"的特性来实现的,它需要一个结构体来作为数组的容器,并且在结构体定义中,最后一个数组成员不指定长度,例如:

cpp 复制代码
struct S
{
	char c;
	int i;
	int arr[0];//未知大小的数组 - 柔性数组成员
};

同一种写法:

上面的一种写法有的编译器会报错

cpp 复制代码
struct S
{
	char c;
	int i;
	int arr[];//未知大小的数组 - 柔性数组成员
};

2. 柔性数组的特点

  • 结构中的柔性数组成员前面必须至少一个其他成员。
  • sizeof 返回的这种结构大小不包括柔性数组的内存。
  • 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大 小,以适应柔性数组的预期大小。

例如我们把上诉结构体的大小计算一下

cpp 复制代码
struct S
{
	char c;
	int i;
	int arr[];//未知大小的数组 - 柔性数组成员
};
int main()
{
	printf("%d\n", sizeof(struct S));
	return 0;
}

运行结果:

3. 柔性数组的使用

使用柔性数组时,我们需要手动分配内存空间,并且调整数组的大小。例如,可以使用malloc函数分配内存空间,并根据实际需要调整数组的大小:

cpp 复制代码
struct S
{
	char c;
	int i;
	int arr[];//未知大小的数组 - 柔性数组成员
};
int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 20);
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	ps->i = 100;
	for (i = 0; i < 100; i++)
	{
		ps->arr[i] = i;
	}
	for (i = 0; i < 100; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	free(ps);
	ps = NULL;
	return 0;
}

运行结果:

4. 柔性数组与其它对比优势

我们来看下面两段代码,其设计是一样的

cpp 复制代码
struct S
{
	char c;
	int i;
	int* data;
};


int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		perror("malloc1");
		return 1;
	}
	ps->c = 'w';
	ps->i = 100;
	ps->data = (int*)malloc(20);
	if (ps->data == NULL)
	{
		perror("malloc2");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->data[i] = i;
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", ps->data[i]);
	}
	//空间不够了,增容
	int* ptr = (int*)realloc(ps->data, 40);
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	else
	{
		ps->data = ptr;
	}
	//增容成功就使用
	//...
	//释放
	free(ps->data);
	ps->data = NULL;
	free(ps);
	ps = NULL;

	return 0;
}

我们在使用malloc给柔性数组开辟内存时,使用完后是需要释放内存的,我们来看它们在内存中的存放

这种开辟的内存空间并不是紧挨着后面开的,而是随便找的一块内存空间,这就导致我们需要多次释放内存。

而柔性数组是紧挨着结构体后开辟的空间,可以直接一次性的释放

cpp 复制代码
struct S
{
	char c;//1
	//3
	int i;//4
	int arr[];//未知大小的数组 - 柔性数组成员
};

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 20);
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	ps->c = 'w';
	ps->i = 100;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}
	//打印
	for (i = 0; i < 5; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//空间不够了
	struct S* ptr = (struct S*)realloc(ps, sizeof(struct S)+40);
	if (ptr != NULL)
	{
		ps = ptr;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	//增容成功后,继续使用
	
	//释放
	free(ps);
	ps = NULL;

	return 0;
}

5. 内存碎片

因为有时内存的开辟不是紧挨着的,而是一块一块的,这就造成了一些内存的浪费,所以有时像柔性数组这样紧挨着开辟的是很有必要的。

相关推荐
番茄灭世神2 小时前
MCU开发常见软件BUG总结(持续更新)
c语言·stm32·单片机·嵌入式·gd32
Ar-Sr-Na3 小时前
STM32现代化AI开发指南-VSCode环境配置(macOS)
c语言·人工智能·vscode·stm32·嵌入式硬件·硬件工程
2301_789015624 小时前
C++:智能指针
c语言·开发语言·汇编·c++·智能指针
weixin_446023564 小时前
C语言开发Win32程序太麻烦?微软不支持有3个原因
c语言·微软·mfc·win32程序·开发难度
程序员zgh5 小时前
C/C++ 单元测试系统 构建
c语言·开发语言·c++·学习·单元测试
孬甭_5 小时前
揭开指针的面纱(中)
c语言
草莓熊Lotso5 小时前
【Linux系统加餐】 mmap 文件映射全解:从底层原理、API 到实战开发(含 malloc 模拟实现)
android·linux·运维·服务器·c语言·c++
深邃-5 小时前
【C语言】-数据在内存中的存储(2):浮点数在内存中的存储
c语言·开发语言·数据结构·c++·算法·html5
智者知已应修善业5 小时前
【51单片机利用外部中断编写程序用两个按键控制数码管显示从0到9,S1控制加计数0—9,S2控制减计数9—0。】
c语言·经验分享·笔记·算法·51单片机
cch89185 小时前
Java vs C语言:编程语言终极对决
java·c语言·开发语言