zoukankan      html  css  js  c++  java
  • C语言变长数组data[0]

    1、前言

      在刷题时遇到一个结构中包含char data[0],第一次见到时感觉很奇怪,数组的长度怎么可以为零呢?于是上网搜索一下这样的用法的目的,发现在linux内核中,结构体中经常用到data[0]。这样设计的目的是让数组长度是可变的,根据需要进行分配,方便操作,节省空间。

    2、data[0]结构

    经常遇到的结构形状如下:

    struct MyData
    {
        int nLen;   //长度
        char data[0];  //起始地址
    };

     在结构中,data是一个数组名;但该数组没有元素;该数组的真实地址紧随结构体MyData之后,而这个地址就是结构体后面数据的地址(如果给这个结构体分配的内容大于这个结构体实际大小,后面多余的部分就是这个data的内容);这种声明方法可以巧妙的实现C语言里的数组扩展。

    实际用时采取这样:
             struct MyData *p = (struct MyData *)malloc(sizeof(struct MyData )+strlen(str))
             这样就可以通过p->data 来操作这个str。

    例如:

    #include <iostream>
    using namespace std;
    
    struct MyData
    {
    	int nLen;
    	char data[0];
    };
    
    int main()
    {
    	int nLen = 10;
    	char str[10] = "123456789";
    	cout << "Size of MyData: " << sizeof(MyData) << endl;
    	MyData *myData = (MyData*)malloc(sizeof(MyData) + 10);
    	memcpy(myData->data, str, 10);
    	cout << "myData's Data is: " << myData->data << endl;
    	free(myData);
    
    	return 0;
    }
    

    输出结果:

    由于数组没有元素,该数组在该结构体中分配占用空间,所以sizeof(struct Mydata) = 4。malloc申请的是14个字节的连续空间,它返回一个指针指向这14个字节,强制转换成struct INFO的时候,前面4个字节被认为是Mydata结构,后面的部分拷贝了“123456789”的内容。   

    写个程序对比char data[0],char *data, char data[],如下所示:

    //VS2015
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct 
    {
    	int len;
    	char data[0];
    }info1;
    
    typedef struct 
    {
    	int len;
    	char* data;
    }info2;
    
    typedef struct 
    {
    	int len;
    	char data[];
    }info3;
    
    int main()
    {
    	printf("sizeof(info1)=%u
    ", sizeof(info1));
    	printf("sizeof(info2)=%u
    ", sizeof(info2));
    	printf("sizeof(info3)=%u
    ", sizeof(info3));
    	
    	info1 buff1;
    	info2 buff2;
    	info3 buff3;
    
    	printf("buff1 address:%p,buff1.len address:%p,buff1.data address:%p
    ",
    		&buff1, &(buff1.len), buff1.data);
    
    	printf("buff2 address:%p,buff2.len address:%p,buff2.data address:%p
    ",
    		&buff2, &(buff2.len));
    		//, buff2.data);
    
    	printf("buff3 address:%p,buff3.len address:%p,buff3.data address:%p
    ",
    		&buff3, &(buff3.len), buff3.data);
    
    	return 0;
    }
    

    输出结果:

    可以看出data[0]和data[]不占用空间,且地址紧跟在结构后面,而char *data作为指针,占用4个字节,地址不在结构之后。

    ps:当buff2.data未注释时,会报错:

     

    3、实际当中的用法

    在实际程序中,数据的长度很多是未知的,这样通过变长的数组可以方便的节省空间。对指针操作,方便数据类型的转换。测试程序如下:

    #include <stdio.h>   // “standard input & output"(标准输入输出)
    #include <stdlib.h>  //标准库头文件,定义了五种类型、一些宏和通用工具函数。
    #include <string.h>
    #include <stdint.h>  //定义了几种扩展的整数类型和宏 
    
    typedef struct
    {
    	int len;
    	char data[0];
    }info1;
    
    typedef struct
    {
    	int len;
    	char *data;
    }info2;
    
    typedef struct
    {
    	int len;
    	char data[];
    }info3;
    
    typedef struct
    {
    	uint32_t id;
    	uint32_t age;
    }student_st;
    
    
    void print_stu(const student_st *stu)
    {
    	printf("id:%u,age:%u
    ", stu->id, stu->age);
    }
    
    int main()
    {
    	student_st *stu = (student_st *)malloc(sizeof(student_st));
    	stu->id = 100;
    	stu->age = 23;
    
    	student_st *tmp = NULL;
    
    	info1 *buff1 = (info1 *)malloc(sizeof(info1) + sizeof(student_st));
    	buff1->len = sizeof(student_st);
    	memcpy(buff1->data, stu, buff1->len);
    	printf("buff1 address:%p,buff1->len address:%p,buff1->data address:%p
    ",
    		buff1, &(buff1->len), buff1->data);
    
    	tmp = (student_st*)buff1->data;
    	print_stu(tmp);
    
    	info2 *buff2 = (info2 *)malloc(sizeof(info2));
    	buff2->len = sizeof(student_st);
    	buff2->data = (char *)malloc(buff2->len);
    	memcpy(buff2->data, stu, buff2->len);
    	printf("buff2 address:%p,buff2->len address:%p,buff2->data address:%p
    ",
    		buff2, &(buff2->len), buff2->data);
    
    	tmp = (student_st *)buff2->data;
    	print_stu(tmp);
    
    	info3 *buff3 = (info3 *)malloc(sizeof(info3) + sizeof(student_st));
    	buff3->len = sizeof(student_st);
    	memcpy(buff3->data, stu, buff3->len);
    	printf("buff3 address:%p,buff3->len address:%p,buff3->data address:%p
    ",
    		buff3, &(buff3->len), buff3->data);
    
    	tmp = (student_st*)buff1->data;
    	print_stu(tmp);
    
    	free(buff1);
    
    	free(buff2->data);
    	free(buff2);
    
    	free(buff3);
    	free(stu);
    	return 0;
    }
    

    输出结果:

      

     采用char *data,需要进行二次分配,操作比较麻烦,很容易造成内存泄漏。而直接采用变长的数组,只需要分配一次,然后进行取值即可。

    (thanks)参考文章:http://www.cnblogs.com/Anker/p/3744127.html

     

  • 相关阅读:
    AtCoder Regular Contest 093
    AtCoder Regular Contest 094
    G. Gangsters in Central City
    HGOI 20190711 题解
    HGOI20190710 题解
    HGOI 20190709 题解
    HGOI 20190708 题解
    HGOI20190707 题解
    HGOI20190706 题解
    HGOI 20190705 题解
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/5283505.html
Copyright © 2011-2022 走看看