C语言结构体中0字节数组(柔性数组)的妙用(附内存排布图解和完整代码)

🧑 博主简介:现任阿里巴巴嵌入式技术专家,15年工作经验,深耕嵌入式+人工智能领域,精通嵌入式领域开发、技术管理、简历招聘面试。CSDN优质创作者,全网11W+粉丝博主,提供产品测评、学习辅导、简历面试辅导、毕设辅导、项目开发、C/C++/Java/Python/Linux/AI等方面的服务,同时还运营着十几个不同主题的技术交流群,如有需要请站内私信或者联系VX(gylzbk),互相学习共同进步。

1. 概述

C语言结构体中的最后一个成员,使用长度为0的数组(或称为柔性数组成员),主要是为了方便的管理内存缓冲区。

c 复制代码
typedef struct {
	int header;
	int length;
	char data[0]; //0字节数组
} flexiable_struct;

由于data长度为0,所以它本身不占用任何内存空间;但它又处在结构体的末尾,所以它所在的位置刚好也是内存中偏移过去结构体大小之后,紧跟着那块内存的起始位置。

2. 原理分析

如上图所示,假设我们申请一块长度大于结构体大小(sizeof(flexiable_struct) + data_length)的内存时,data刚好就指向了多出来这块data_length长度内存的起始位置,这部分多出来的内存我们可以作为自定义数据来灵活使用。由于这块内存是跟着结构体一起一次申请来的,所以等到使用完成之后,也只需要释放结构体指针就可以一次性把结构体和这块自定义数据的内存一同释放掉了。

c 复制代码
typedef struct {
	int header;
	int length;
	char *data; //0字节数组
} flexiable_struct;

如果直接使用指针而不使用0字节数组。

在分配内存时,就必须先给结构体分配一块长度为sizeof(flexiable_struct)内存,然后在给结构体的data指针分配一块长度为data_length的内存。而此时分配的2块内存已经不连续了,所以在使用完成之后,要分别进行释放,而且还需要先释放data内存,再释放结构体内存,顺序还不能反。

相比而已,如果使用0字节数组,则只需要一次申请就可以全部分配出来所有所需的内存。反过来,释放时也是一样,一次释放就可以一次释放掉所有内存。0字节数组的机制本质上就是分配一段连续的的内存,减少了内存的碎片化,提高了程序访问效率。同时,由于简化了代码,程序可读性也大大提升,出bug的概率也大幅减小,程序稳定性有了更好的保障。

0字节数组在C语言规范中的支持始于C99标准。在某些比较老的编译器中,使用长度为0的数组可能会引发问题或未定义的行为。因此,在使用之前,请确保项目所使用的编译器能够支持C99以及以后的标准。

3. 使用场景

作为结构体中的0字节数组,因为它的灵活,所以一般用在需要动态分配内存的场景中,以便在运行时确定数组的实际大小 。这种技术特别适用于那些大小可变的数据结构,其中数组的大小在编译时无法确定,需要在运行时根据具体需求来确定。这样,可以动态分配足够的内存来容纳实际的数据,而无需在编译时确定数组的大小。

例如,可以创建一个结构体来表示一个网络协议的消息,其中包含一个消息头和一个可变长度的消息体。消息体可以使用0字节数组来表示,以便在运行时根据不同的消息头来动态分配不同长度的内存来存储实际的消息内容。

需要注意的是,使用0字节数组时,必须确保在分配内存时为其分配足够的空间,并在使用之前正确设置数组的大小。此外,由于0字节数组不占用空间,因此在使用结构体时需要注意内存对齐和内存布局的问题,以确保正确地访问和操作数组元素。

4. 示例代码

下面是一个使用0字节数组成员的例子:

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

//预定义好测试数据
#define DATA_CONTENT "hello world!"

// 定义一个结构体,包含一个数据长度和一个0字节数组成员
typedef struct {  
    int length;  // 用来存储data长度
    char data[0];    // 0字节数组成员,实际上不占用空间  
} flexible_struct;  

int main(int argc, char *argv[])
{
    // 定义一个flexible_struct结构体指针
    flexible_struct *test = NULL;

	//计算一下我们用来存储的数据长度
	int len = strlen(DATA_CONTENT);

	//根据数据长度给test指针分配内存,只需要申请1次即可
	test = malloc(sizeof(flexible_struct) + len + 1 );
	
	//给结构体test进行赋值,将数据及其长度存入结构体
	test->length = len;
	strcpy(test->data, DATA_CONTENT);
	
    // 数据使用中(打印一下我们存入的数据内容)
	printf("get data:'%s', data length:%d\n", test->data, test->length); 

    // 使用完成,只需要释放1次内存即可  
    free(test);
    
    return 0;  
}

代码注释已经写的很清楚,这里就不再赘述了。使用gcc编译运行,直接看效果:

5. 总结

总的来说,0字节数组作为一种灵活且高效的内存管理技术,在C语言高级编程中具有广泛的应用前景。通过深入理解其原理和使用场景,我们可以更好地利用这一技术来简化程序代码、优化内存使用和提高程序的性能。希望本文能够帮助读者更好地理解和应用0字节数组,并在实际编程中发挥其优势。

相关推荐
KeithTsui25 分钟前
C语言之 比特(bit)、字节(Byte)、字(Word)、整数(Int)
linux·c语言·开发语言·c++·算法·word
梁下轻语的秋缘5 小时前
每日c/c++题 备战蓝桥杯(洛谷P1440 求m区间内的最小值 详解(单调队列优化))
c语言·c++·蓝桥杯
林开落L6 小时前
C语言:基础篇之常见概念
c语言·开发语言
一匹电信狗6 小时前
【数据结构】队列的完整实现
c语言·数据结构·c++·算法·leetcode·排序算法·visual studio
tadus_zeng7 小时前
C/C++ 整数类型的长度
c语言·开发语言·c++
浩皓素16 小时前
深入理解For循环及相关关键字原理:以Python和C语言为例
c语言·python
小贾要学习18 小时前
【C语言】贪吃蛇小游戏
c语言·开发语言·游戏
人类恶.18 小时前
C 语言学习笔记(函数2)
c语言·笔记·学习
yanjiee1 天前
Cursor无法使用C/C++调试的解决办法
c语言·开发语言·c++·vscode
菜菜why1 天前
esp32课设记录(五)整个项目开源github
c语言·esp32