您的位置:首页 > 其它

变长结构体的应用

2016-02-29 22:30 309 查看
顾名思义,结构体长度是“可变”的。但是这个可变不针对sizeof()函数。

用例代码:

//弹性数组的大小,各对象是否都不一样?
//如果都一样,怎么看空间大小,用sizeof array来加?
//但是如果是对象,也没法看,因为是指针指向对象的形式
//用的时候,申请可以是这样
#include<malloc.h>
#define ARRAY_SIZE 200
struct 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 8
strict pointer's size:4
sizeof array : 0
strlen array: 5
hello
struct's size 8
strict pointer's size:4
sizeof array : 0
strlen array: 5
hello
p3->array:hello world
p3->array:hello world
p3->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 200
struct 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 28
strict pointer's size:4
sizeof arrayNickname : 0
strlen arrayNickname: 5
array:hello
arrayNickname:hello
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息