变长结构体的应用

来源:互联网 发布:如何编写抢购软件 编辑:程序博客网 时间:2024/05/22 07:53

顾名思义,结构体长度是“可变”的。但是这个可变不针对sizeof()函数。


用例代码:

//弹性数组的大小,各对象是否都不一样?//如果都一样,怎么看空间大小,用sizeof array来加?//但是如果是对象,也没法看,因为是指针指向对象的形式//用的时候,申请可以是这样#include<malloc.h>#define ARRAY_SIZE 200struct S{int* a;int *b;char array[0];};struct S2{int* a;int *b;char array[];//另一种更稳妥的形式,而前者可能编译报错};struct S3{int a;char *array;};int main(){        struct S* p = (struct S*)malloc(100);        strcpy(p->array,"hello");        printf("struct's size %d\n",sizeof(struct S));        printf("strict pointer's size:%d\n",sizeof(p));        printf("sizeof array : %d\n",sizeof(p->array));        printf("strlen array: %d\n",strlen(p->array));        printf("%s\n",p->array);//用的时候,申请可以是这样        struct S* p2 = (struct S*)malloc(sizeof(struct S) + ARRAY_SIZE);        struct S2* pS2 = (struct S2*)malloc(sizeof(struct S2) + ARRAY_SIZE);        strcpy(p2->array,"hello");        printf("struct's size %d\n",sizeof(struct S2));        printf("strict pointer's size:%d\n",sizeof(p2));        printf("sizeof array : %d\n",sizeof(p2->array));        printf("strlen array: %d\n",strlen(p2->array));        printf("%s\n",p->array);        struct S3* p3 = (struct S3*)malloc(sizeof(struct S3));        p3->array = (char *)malloc(ARRAY_SIZE);        strcpy(p3->array,"hello world");        printf("p3->array:%s\n",p3->array);        //free(p3->array);        //改变顺序运行也不报错,给free传参就不算访问了?        //p3已经free了,还能访问p3->array?        free(p3);        printf("p3->array:%s\n",p3->array);        free(p3->array);//访问其实都能访问,就是不确保对了吧        printf("p3->array:%s\n",p3->array);}


打印输出:

struct's size 8strict pointer's size:4sizeof array : 0strlen array: 5hellostruct's size 8strict pointer's size:4sizeof array : 0strlen array: 5hellop3->array:hello worldp3->array:hello worldp3->array:hello world



总结:sizeof看结构体,只有实体数据和指针占空间,char array[0]是不占长度的。

变长结构体的0长度数组有两种声明方法(见S1和S2),不影响sizeof()对结构体大小的判断。

变长结构体S1与S2是为了达到和S3相同的效果而生的,具体内容的访问上也有些类似。

应用上,必须用堆空间,指针的应用也很巧妙,指向紧跟结构体数组的位置。至于后边的为什么能用,因为后边空间是malloc或new来的一大片连续空间的一部分。

如果堆空间的申请/销毁的资源开支大与效率低是个劣势的话,可能优势就在于和S3的二次申请/销毁比,开支还会小点。这样选择也肯定是非这么用不可的时候了。比如我要接动态的数据,打包并发送,数据包的头部分肯定是固定的,但是尾部,内容具体有多长不确定,如果都以最大长度来申请,会很耗费内存。

struct s* ps = malloc(sizeof(struct S)+strlen(string1));//比如是字符串,有了变长结构体,我就我就能strlen()一下获取长度,再去申请合适的空间

有一个问题无解,sizeof()结构体是固定长度,sizeof()对象都是多长?因为动态申请时你只拿到了指针,所以看不到对象长度,只能看到4(32位机)。

注意:据说,按理说也是,如果用S3,必须先释放array的空间,再释放S3结构体对象的空间。但是感觉上顺序颠倒也能行,这是因为删除数据的原则只是不再用,而不是去改变内存具体的电容存储内容,巧合罢了,但是很危险,属于越界行为。如果是动态运行,应该就会出错了(不过在另一个blog中我在linux gcc的爆堆实验没怎么成功,就是说,即使free过,也会耗尽资源,总之不能重复涂抹一处空间)


===========================================

以前IM的项目里别人的代码中,有个用法,感觉是错误的,至少不是变长结构体的用法,也许是重用名的用法?创建一个别名!也许是不懂变长结构体,迭代的时候胡乱修改,成这样了。这个结构体的长度是36==16+6+6+4,0长度数组的特性还在,倒是可以实现一个成员的重命名功能,也许真是为了干这个的,不过就是提醒一下,零长度数组必须放到末尾才能起到变长结构体的效果,并且必须是动态申请的堆空间。动态申请的你只能用指针访问,所以也无从获取对象长度,所以要谨慎判断变长结构体的边界。

// 注册typedef struct{long long m_llUserId; // 用户名char m_pcPsw[0];// 密码char ShamPsw[16];// 忽略char m_pcVerCode[0];// 验证码char ShamVerCode[6];// 忽略char m_pcCode[0];// 邀请码char ShamCode[6];// 忽略}TRegisterData;

下面演示一下别名(Nickname)的用法:

#include<stdio.h>#include<malloc.h>#define ARRAY_SIZE 200struct S2{int* a;int *b;//char arrayNickname[];//不写0的话,定义非变长结构体时编译不过去char arrayNickname[0];//更稳妥的写法char array[18];};int main(){        struct S2* pS2 = (struct S2*)malloc(sizeof(struct S2) + ARRAY_SIZE);        strcpy(pS2->array,"hello");        printf("struct's size %d\n",sizeof(struct S2));        printf("strict pointer's size:%d\n",sizeof(pS2));        printf("sizeof arrayNickname : %d\n",sizeof(pS2->arrayNickname));        printf("strlen arrayNickname: %d\n",strlen(pS2->arrayNickname));        printf("array:%s\n",pS2->array);        printf("arrayNickname:%s\n",pS2->arrayNickname);}

struct's size 28strict pointer's size:4sizeof arrayNickname : 0strlen arrayNickname: 5array:helloarrayNickname:hello



0 0