【c】柔性数组

前言:

C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员,本文将介绍柔性数组的两种方案。


一、第一种

(一)创建

在具有两个以上成员的结构体中,最后一个成员为数组,且数组的大小是未知的,这个数组就是柔性数组,数组表示未知的方式可以是'[ ]'或是'[0]'。

例:

struct bt
{
	int a;
	int arr[];//int arr[0]
};

(二)柔性数组的特性

①sizeof 返回的这种结构大小不包括柔性数组的内存。
因为柔性数组是未知大小的数组,所以sizeof在计算结构体大小时,不会计算柔性数组成员的大小。

②结构中的柔性数组成员前面必须至少一个其他成员。                                                                  因为柔性数组是未知大小的数组,所以编译器没法为其分配内存。

③包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。                                                                                              因为柔性数组依赖malloc函数分配内存,为使柔性数组符合预期大小,不至于为空,所以分配的内存应该大于结构体的大小。

例:

#include 
#include 

struct bt
{
	int a;//至少包含一个其他成员
	char b;
	int arr[];//int arr[0]
};
int main()
{
	//结构体大小计算
	printf("bt = %d\n", sizeof(struct bt));
	//预期为可存十个整形的数组
	struct bt* s = (struct bt*)malloc(sizeof(struct bt) + 10*sizeof(int));
	//返回值检测
	if (s == NULL) return 1;
	//使用柔性数组
	for (int i = 0; i < 10; i++)
	{
		s->arr[i] = i + 1;
		printf("%d ", s->arr[i]);
	}
	//回收动态内存
	free(s);
	s = NULL;
	return 0;
}

 (三)动态内存管理

1.柔性数组内存分配

包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。”

推荐格式:(struct 名*)malloc(sizeof(struct 名) + 预期大小*sizeof(元素类型))

2.柔性数组内存增减

类似于柔性数组内存分配,我们可以使用realloc函数对分配给结构体的内存进行增减,直接改变柔性数组的大小。

推荐格式:(struct 名*)realloc(sizeof(struct 名) + 预期大小*sizeof(元素类型))

注意:不要忘记进行返回值检测,和动态内存释放。

二、类柔性数组

柔性数组本质是一个动态的数组,内存处于堆区,是结构体的最后一个成员,这三点都是很好模拟的属性,我们将动态内存管理及指针、结构体的知识结合起来,以另一种方式实现一个类柔性数组也是可以的。

(一)模拟

模拟属性①结构体的最后一个成员,实现方式:

将模拟的类柔性数组放在结构体的最后。

模拟属性②内存处于堆区,实现方式

很简单,用malloc函数为结构体分配内存即可。

模拟属性③是一个动态的数组,实现方式:

动态的数组是无法直接表示的,如果采用位置大小数组的方法,那和第一种方法就没有区别了。

我们知道,数组名=数组首地址,因而,我们可以不直接在结构体的最后放一个数组,而是放一个指针,指针指向一块堆区的动态内存块。

(二)构建

#include 
#include 
struct bt
{
	int a;
	char b;
	int* arr;
};
int main()
{
	struct bt* s = (struct bt*)malloc(sizeof(struct bt));
	if (s == NULL) return 1;
	//类柔性数组
	s->arr = (int*)malloc(10 * sizeof(int));
	if (s->arr == NULL) return 1;
	//使用
	for (int i = 0; i < 10; i++)
	{
		s->arr[i] = i + 1;
		printf("%d ", s->arr[i]);
	}
	//释放动态内存
	free(s->arr);
	s->arr = NULL;
	free(s);
	s = NULL;
	return 0;
}

 值得注意的是,类柔性函数要比结构体先释放,因为如果结构体先释放就找不到类柔性数组的地址了,没有地址便无法释放。(free函数释放内存后,该内存块重置为随机数)

三、两种方法对比

方法一的好处

第一个好处是:方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给
用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你
不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好
了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
第二个好处是:这样有利于访问速度.
连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正
你跑不了要用做偏移量的加法来寻址)
 

内存的存储:

【c】柔性数组_第1张图片

【c】柔性数组_第2张图片 

 

你可能感兴趣的:(C语言学习笔记,入门到懵逼,柔性数组,c语言,学习,开发语言)