C语言变长数组data[0]的强大意义

­以前一直写结构体时都是用char *data来表达结构体存储可变的数据,这样的做法是非常正常也是常用的形式,前段时间看部分代码时发现一个结构中包含char data[0],第一次见到非常不理解,数组的长度居然可以为0?当时就google了一下,发现很多Linux上的源码中都采用char data[0],想到大神们都采用这种写法,说明这种写法肯定有隐藏着非常观的空间优势或者操作上的方便。为此我决定写个demo来测试一下

  1. 写个程序来对比下char *data,char data[]跟char data[0]的有何不同
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef struct
    {
    	int   len;
    	char *data;
    } buff_point;
    
    typedef struct
    {
    	int  len;
    	char data[];
    } buff_array;
    
    typedef struct
    {
    	int  len;
    	char data[0];
    } buff_zero;
    
    int main()
    {
    	printf("sizeof(buff_point)=%u\n", sizeof(buff_point));
    	printf("sizeof(buff_array)=%u\n", sizeof(buff_array));
    	printf("sizeof(buff_zero)=%u\n", sizeof(buff_zero));
    
    	buff_point buff1;
    	buff_array buff2;
    	buff_zero  buff3;
    
    	printf("buff1 address:%p,buff1.len address:%p,buff1.data address:%p\n", &buff1, &(buff1.len), buff1.data);
    	printf("buff2 address:%p,buff2.len address:%p,buff2.data address:%p\n", &buff2, &(buff2.len), buff2.data);
    	printf("buff3 address:%p,buff3.len address:%p,buff1.data address:%p\n", &buff3, &(buff3.len), buff3.data);
    
    	return 0;
    }

测试结果:

test.result

从上面可以看出data[0]和data[]是地址紧跟在结构后面,内存连续的,而char *data作为指针,占用多8个字节,地址不在结构之后,所以内存地址是不连续的。(PS.指针占用的空间是跟系统有关的,32位系统则为4个字节,64位系统则占用8位字节)

总结

采用char data[]或char data[0]的结构中,data是一个数组名;但该数组没有元素;该数组的真实地址紧随结构体之后,而这个地址就是结构体后面数据的地址(如果给这个结构体分配的内容大于这个结构体实际大小,后面多余的部分就是这个data的内容);这种声明方法可以巧妙的实现C语言里的数组扩展。顺便来跟char *data来对比下操作。

假设我们有个数据要进行传送

typedef struct
{
    uint_32 sn;
    uint_32 age;
} student_st;

char *data的内存操作代码

buff_point *buff;
student_st *stu = (student_st *)malloc(sizeof(student_st));
stu->sn = 100;
stu->age = 23;
buff = (buff_point *)malloc(sizeof(buff_point));
buff->len = sizeof(student_st);
buff->data = (char *)malloc(buff->len);
memcpy(buff->data, stu, buff->len);
//释放
free(buff->data);
free(buff);
free(stu);

char data[]或char data[0]的内存操作代码

buff_zero *buff;
student_st *stu = (student_st *)malloc(sizeof(student_st));
stu->sn = 100;
stu->age = 25;
buff = (buff_zero *)malloc(sizeof(buff_zero) + sizeof(student_st));
buff->len = sizeof(student_st);
memcpy(buff->data, stu, buff->len);
//释放
free(buff);
free(stu);

由上面的代码大家可以看到明显的优势了吧,内存空间相差8个字节,这个没什么,但是在内存分配跟释放来说那可是非常明显的优势,由于采用char *data指针类型,导致data跟结构体的分配地址是不连续的,所以在分配内存是必须在为data分配内存的,导致在释放内存时也必须先对data进行释放后在释放结构体,试想下如果忘记先释放data分配的内存,就释放了结构体,那就会引起内存孤岛,导致内存泄漏。而采用char data[]或char data[0],内存是连续的,所以只需释放一次就可,操作简单方便。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注