柔性数组(C语言)

文章目录

  • [1. 柔性数组的定义](#1. 柔性数组的定义)
  • [2. 柔性数组的特点](#2. 柔性数组的特点)
  • [3. 柔性数组的使用](#3. 柔性数组的使用)
  • [4. 柔性数组的好处](#4. 柔性数组的好处)

也许你从来没有听说过 柔性数组 这个概念,但是它确实是存在的。柔性数组是C语言中一种特殊的结构,它允许在结构体的末尾定义一个可变长度的数组。

1. 柔性数组的定义

柔性数组是在C99中的一种玩法,它有两种定义方式,当其中一种定义方式,编译器编译不通过的时候,可以换另一种方式。
方式一:

c 复制代码
typedef struct st_type
{
 int i;
 int a[0];//柔性数组成员
}type_a;

方式二:

c 复制代码
typedef struct st_type
{
 int i;
 int a[];//C99的玩法是:int a[]; 没有指定数组长度
}type_a;

2. 柔性数组的特点

  1. 结构中的柔性数组成员前面必须至少一个其他成员。

这是因为柔性数组的大小是不确定的,所以编译器需要知道其他成员的大小和偏移量。

  1. sizeof 返回的这种结构大小不包括柔性数组的内存。

这是因为柔性数组的大小是可变的,因此 sizeof 返回的是结构体的固定部分的大小。

  1. 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
c 复制代码
struct S
{
    int a;
    char data[]; // 柔性数组成员
};

 struct S* str = malloc(sizeof(struct S) + 20); // 20是柔性数组的最大长度

3. 柔性数组的使用

以下代码,演示了柔性数组的用法:

c 复制代码
#include <stdio.h>
#include <stdlib.h>

struct S
{
	int n;
	int data[]; // 柔性数组成员
};

int main() {
	// 创建包含柔性数组的结构体,并分配足够大的内存
	struct S* s = malloc(sizeof(struct S) + 20); // 20是柔性数组的最大长度

	if (s == NULL)
	{
		perror("malloc");
		return 1;
	}

	s->n = 10;
	for (int i = 0; i < 5; ++i)
	{
		(s->data)[i] = i;
	}
	for (int i = 0; i < 5; ++i)
	{
		printf("%d ", (s->data)[i]);
	}
	free(s); // 释放内存
	s = NULL;
	return 0;
}

上面这段代码的意思是:我想分配一个不定长的数组,于是我有一个结构体,其中有两个成员,一个是n,一个是data。其实上述结构也可以通过指针运算和动态内存分配来实现。关于动态内存分配的知识,可以参考之前写的一篇文章:动态内存管理(malloc calloc realloc free)--- C语言

c 复制代码
#include <stdlib.h>
#include <string.h>

// 定义结构体,包含柔性数组
struct S
{
    int len; // 柔性数组的长度
    int* data; // 柔性数组成员
};

int main() 
{
    // 定义结构体指针
    struct S* s = (struct S*)malloc(sizeof(struct S));
	s->len = 5;
    // 给柔性数组的部分分配内存
    s->data = (int*)malloc(5 * sizeof(int)); // 假设柔性数组存储5个整数

    // 初始化柔性数组
    for (int i = 0; i < s->len; i++) 
    {
        s->data[i] = i;
    }

    // 访问柔性数组的元素
    printf("柔性数组的内容: ");
    for (int i = 0; i < s->len; i++) 
    {
        printf("%d ", s->data[i]);
    }

    printf("\n");

    // 释放内存
    free(s);
    s = NULL;

    return 0;
}

看到这里,你会说,把data声明成一个指针,然后为它再分配一下内存好像也可以也能完成我们预期的效果,那为什么还要搞出来一个0长数组呢?有啥意义呢?答案很简单,就是搞出来柔性数组,其实就是我们想给一个结构体内的数据分配一个连续的内存!

4. 柔性数组的好处

通过上面的介绍,我们知道柔性数组的存在就是想给一个结构体内的数据分配一个连续的内存!那这样做有什么好处呢?
第一个是,方便内存释放。

如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以我们不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

在使用柔性数组的时候,空间是一次性开辟好的,释放空间的时候只需要释放一次;而我们在模拟实现柔性数组的时候,是先给结构体开辟了空间,然后在结构体内进行了二次内存分配,因此在释放空间的时候也需要释放两次,然而释放的顺序也是有讲究的,要先释放data指向的空间,在释放结构体的空间,如果顺序反了,会导致data指向的空间无法被主动释放,会导致内存泄露。

第二个是,这样有利于访问速度。

连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)

  1. 含柔性数组的结构体在开辟空间的时候,是一次性开辟好的,在内存中是一片连续的空间。

  2. 模拟含柔性数组的结构体在内存中是这样开辟空间的:

    这种在内存中开辟空间的方式,可能会导致内存碎片的问题。内存碎片是指未被使用的小块内存,它们可能夹在已分配内存的中间,导致内存浪费。

    而数据在内存中连续存储时,碎片化的可能性较低,因为数据被一起分配并存储。

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。

创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !!!

相关推荐
程序员卷卷狗2 小时前
JVM 调优实战:从线上问题复盘到精细化内存治理
java·开发语言·jvm
lly2024062 小时前
ASP Folder:深入解析其功能与使用技巧
开发语言
雪域迷影3 小时前
Go语言中通过get请求获取api.open-meteo.com网站的天气数据
开发语言·后端·http·golang·get
deng-c-f4 小时前
配置(4):VScode c/c++编译环境的配置:c_cpp_properties.json
c语言·c++·vscode
ysdysyn5 小时前
C# 进程管理实战:检查与启动EXE程序的完整指南
开发语言·c#
IDOlaoluo5 小时前
PHP-5.2.1.tar.gz 离线安装教程:从源码编译到配置的详细步骤(附安装包)
开发语言·php
wangjialelele5 小时前
Qt中的常用组件:QWidget篇
开发语言·前端·c++·qt
爱上妖精的尾巴6 小时前
5-26 WPS JS宏数组元素添加删除应用
开发语言·前端·javascript·wps·js宏
_OP_CHEN6 小时前
C++进阶:(三)深度解析二叉搜索树原理及实现
开发语言·数据结构·c++·二叉树·二叉搜索树·键值对
wxxka6 小时前
git使用
开发语言·git