柔性数组详细讲解

本文介绍了柔性数组在编程中的优势,如动态调整大小、节省内存、提高效率等,并详细展示了malloc、realloc在柔性数组开辟和扩展空间中的应用,以及两种不同空间管理方案的比较,强调了第一种方案的内存释放便利性。
摘要由CSDN通过智能技术生成

动态内存函数的使用和综合实践-malloc,free,realloc,calloc-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Jason_from_China/article/details/137075045

柔性数组存在的意义

 柔性数组在编程语言中指的是可以动态调整大小的数组。相比固定大小的数组,它们提供更大的灵活性,主要存在以下意义:


1. **动态调整大小**:

在程序运行过程中,如果需要增加或减少数组的大小,柔性数组可以避免创建新的数组和复制元素到新数组中的开销。


2. **节省内存**:

柔性数组在初始化时不需要指定确切的大小,因此可以在不知道确切需求的情况下启动程序,节省了初始化的时间和内存空间。


3. **提高效率**:

由于不需要预先分配固定大小的内存,柔性数组可以在数组实际需要的大小上分配内存,减少了内存的浪费。


4. **易于扩展**:

当程序需求变化,需要增加存储空间时,柔性数组更容易进行扩展。


5. **减少代码复杂性**:

通过动态内存管理,程序员可以简化代码,不必担心数组大小的问题。


6. **灵活的数据处理**:

在处理数据时,如果数据量不稳定或者在处理过程中数据量发生变化,柔性数组可以更有效地处理这些情况。
在不同的编程语言中,如C++中的`vector`,Java中的动态数组,都是柔性数组的实现。这些数据结构在现代软件开发中非常常见,因为它们提供了一种高效、灵活的方式来处理动态变化的数据集合。

———————————————————————————————————————————

柔性数组建立在结构体里面

而且是最后一个成员(这里一定要记住,是最后一个成员)

数组没有指定大小

这个数组才是柔性数组

至少有一个其他成员 (柔性数组的条件)-->判断条件

——————————————————————————————————————————— 

柔性数组写法1

—————————————————————————————————————————— 

柔性数组写法2

至少有一个其他成员 (柔性数组的条件)

———————————————————————————————————————————

柔性数组的如何在计算机里面计算的 

内存---这里只计算n的空间,不计算柔性数组arr的空间,

不计算 柔性数组的空间,这里通过计算机的计算,我们发现确实是这样

———————————————————————————————————————————

柔性数组开辟空间的使用逻辑(重点)

首先给出一个代码 我们详细解释代码的逻辑

那么柔性数组在这里面是如何使用的呢

1.首先我们进入主函数这里开辟一个空间,空间的大小是一个结构体大小的空间,这里是计算的大小是不包括弹性数组的大小的,计算的是弹性数组之前的大小,因为弹性数组在正式使用之前是没有大小空间这一说的。

malloc(sizeof(struct s));

2.我们开辟完空间之后,如果是按照正常的开辟空间来说,那么此时开辟的空间只需要进行强制类型转化就可以结束了。但是我们这里讲解的是柔性数组,也就是还没有结束。

malloc(sizeof(struct s)+5*sizeof(int));

3.柔性数组的开辟空间,也就是,结构体空间(不包含弹性数组的大小的空间)+你希望的空间大小。因为你的结尾处是有弹性数组的,弹性数组是可以任意变化的。所以后面的加上,加上的是可以变化的空间,也就是弹性数组的空间 ,当然,你要是不加上空间也是可以的。最后进行强制类型转化,并且创建指向这个空间的变量。

struct s*ps=(struct s*)malloc(sizeof(struct s)+5*sizeof(int));

也就是这样用指针进行接收,强制类型转化为结构体,因为是结构体类型的,自然需要用结构体进行接收,结构体进行强制类型转换。

这段代码的图解

这段代码意味着

四个字节给n

20个字节给arr

把这个地址给ps

这里ps指向的是ps这一框空间

这里也可以通过realloc调整空间

柔性数组为什么放到后面:

也就是 结构体的这个大小是柔性变化的

所以需要放到后面 方便空间的柔性

使用

柔性数组

———————————————————————————————————————————

柔性数组延长开辟空间的使用逻辑(重点)

这里神奇的来了 realloc函数可以二次对空间进行扩展。

这里可以进行扩展空间

1,malloc在弹性数组里面的使用(上面讲解复制来的)

1.首先我们进入主函数这里开辟一个空间,空间的大小是一个结构体大小的空间,这里是计算的大小是不包括弹性数组的大小的,计算的是弹性数组之前的大小,因为弹性数组在正式使用之前是没有大小空间这一说的。

malloc(sizeof(struct s));

2.我们开辟完空间之后,如果是按照正常的开辟空间来说,那么此时开辟的空间只需要进行强制类型转化就可以结束了。但是我们这里讲解的是柔性数组,也就是还没有结束。

malloc(sizeof(struct s)+5*sizeof(int));

3.柔性数组的开辟空间,也就是,结构体空间(不包含弹性数组的大小的空间)+你希望的空间大小。因为你的结尾处是有弹性数组的,弹性数组是可以任意变化的。所以后面的加上,加上的是可以变化的空间,也就是弹性数组的空间 ,当然,你要是不加上空间也是可以的。最后进行强制类型转化,并且创建指向这个空间的变量。

struct s*ps=(struct s*)malloc(sizeof(struct s)+5*sizeof(int));

也就是这样用指针进行接收,强制类型转化为结构体,因为是结构体类型的,自然需要用结构体进行接收,结构体进行强制类型转换。

2,realloc在弹性数组里面的使用讲解:

1.首先我们知道realloc函数的使用规则,realloc(目标函数,扩展的空间的大小),同时realloc使用的时候可能会导致开辟空间的失败,所以我们需要先拿指针进行接收,再进行判断和赋值。

2.我们需要知晓弹性数组的使用规则,也就是sizeof计算的是字节的大小是不包含弹性数组的。所以需要加上你需要的实际的空间的大小。也就是,原本20个字节的大小,你扩展40,那么加一起就是60空间的大小。你可以不使用,但是使用的时候,最多可以使用的是60个空间的大小。

3.接下来我们进行代码的解释,malloc的代码逻辑是一样的,所以我们从realloc开始讲解,这里的我们直接使用realloc是可能开辟空间导致失败的,所以我们选择用一个指针指向开辟的空间,只要不是空地址,我们就继续下面的工作。也就是

int *ptr=(struct s*)realloc(ps,sizeof(struct s)+10*sizeof(int));

解释:这里开辟的是ps指向的空间,创建指针变量指向ps指向的空间,防止创建的时候失败,导致销毁。

4.总结使用代码,想要进行赋值,打印出来,最后我给出了代码。

柔性数组第一种的代码总结

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct s
{
	int i;
	int arr[];
};
//sizeof(struct s):这个表达式计算了 struct s 类型的大小。
// 这包括了 struct s 中所有字段的大小,但不包括动态分配的数组 arr 的大小,
// 因为数组的大小取决于它所包含的元素的数量。
// struct s 中的 int i 字段占用4个字节(在大多数现代平台上是这样),
// 而 int arr[] 是一个未指定大小的数组,所以我们不知道它占用的空间 
// 而后面 我们进行数组的使用的时候 +也就是加上想要延长的数组的长度,
// 所以这也就是为什么柔性数组是需要放到结构体最后的
int main()
{
	//这里是内存空间的扩展
	struct s* ps = (struct s*)malloc(sizeof(struct s) + 5 * sizeof(int));
	if (ps == NULL)
	{
		perror("struct:");
		return 1;
	}

	for (int i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	struct  s pf = { .i = 1 };
	printf("\n%d\n", pf.i);

	//这里我们认为开辟的空间是5个整形的空间大小 所以我们需要进行这个,对这个弹性数组进行realloc
	struct s* ptr = (struct s*)realloc(ps, sizeof(struct s) + 10 * sizeof(int));
	if (ptr == NULL)
	{
		perror("realloc:");
		return 1;
	}
	ps = ptr;
	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	free(ps);
	return 0;
}

———————————————————————————————————————————

柔性数组扩展空间的第二种实现方案(补充说明)

这里可以放到堆上,也就是先开辟空间,因为柔性数组本身就是弹性的

然后判断是不是空指针,不是继续运行 

进入正题

这里给出五个变量,这里是单独给到柔性数组里面,和版本1不一样。

版本1里面是对整个数组进行内存延伸,这个是连续的

版本2里面是开辟一块一块的内存空间,这个不是连续的

 这样第二种会导致一种情况,

释放的时候需要先释放空间2,再释放1,需要先释放2的空间,不然是找不到2的空间,后释放ps空间。因为正常情况下1,2空间之间还有空间是不被利用的。那么你要是先释放空间1,就会导致找不到后面的空间。

但是第一种就不需要,只需要释放空间1 。

———————————————————————————————————————————

总结

还是第一种方案好

以为malloc使用次数越多

空间碎片越多

空间利用率越小

柔性数组 的优势方案 1 方便内存释放

不像第二种方案 结构体包含指针 需要释放两次

第二个方案 不是连续的空间 所以第一个使用起来方便 方便管理

文章推荐

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

内存的划分 

这里附带两章内存划分图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值