变长数组
之前遇到过这个,当时好像也是明白了,但过后就有点忘记了,或者说思路不清,今天有空写了个博客。
我们有这样的需求,比如我们声明了一个结构体变量,SMsg msg,我们可以直接通过这个变量访问到缓冲区msg.buff对其进行操作,换句话说得找个变量来标识这段缓冲区的地址。
考虑以下情况,我们想声明一个结构体SMsg,这个结构体有以下成员。
1. msgid ,int型 用来表示这个结构体的id
2. buffsize unsigned int 类型,表示这个结构体的缓冲区大小
3. buff, 结构体的缓冲区,额,这个声明成什么类型呢???
解决办法:
1. 我们可以声明成一个char *类型
结构体定义如下:
struct SMsg
{
intmsgid;
unsigned intbuffsize;
char *buff;
};
当我想使用一个缓冲区大小是16的这个结构体,我可以这样声明。
SMsg*msg=(SMsg*) malloc(sizeof(SMsg)+16);
msg->buffsize=16;
msg->buff=(char*)malloc(16);
想要使用缓冲区内容时,我们可以使用msg->buff 对其进行操作。
而当释放时,我们也必须 free(msg->buff); free(msg);对其进行释放。
这样有没有觉得很麻烦,确实这样,而且这样容易出错,忘记为buff分配内存,我记得在青岛实训时,有个同学就遇到过这样的问题。
2.我们可以改进一下。声明成这样
#define MAX_BUFFER_SIZE1024
struct SMsg
{
int msgid;
unsigned int buffsize;
char buff[MAX_BUFFER_SIZE];
};
这样我们就不必为整个结构体来分配内存了可以这样操作
SMsg *msg=(SMsg*)malloc(sizeof(SMsg));
msg->buffsize=16;
我们可以用msg->buff来访问数据。
使用完成后用free(msg);来释放
3.第二种方法有种不好的地方就是会浪费内存,对吧我们只需要16个字节,它一下给我分配了1024个,不像第一种方法那样想要多少分配多少。现在该变长数组登场了,
它结合了上面两种方法的优点,请看:
struct SMsg
{
int msgid;
unsigned int buffsize;
char buff[0];
};
对你没有看错,数组的长度是0。然后你可以看看这个结构体的大小,在32位下是8,那个buff并没有占用内存。
我们怎么使用这个东西呢?现在我们同样是想使用大小为16的缓冲区。
SMsg *msg=(SMsg*)malloc(sizeof(SMsg)+16);
msg->buffsize=16;
可以直接使用msg->buff来对缓冲区进行操作。
使用完后,我们可以直接使用free(msg)来对其进行释放,是不是使用起来很方便。
为什么可以这样使用呢?我们来做个实验。
struct SChangeLenPack
{
intbodySize;
charbody[0];
};
struct Node
{
intbodysize;
char*data;
};
int main()
{
SChangeLenPackpack;
printf("结构体的大小是:%d\n",sizeof(SChangeLenPack));
printf("结构体开始地址:%p,数据包开始地址:%p:\n",&pack,&pack.body);
printf("\n");
Node node;
printf("结构体的大小是:%d\n",sizeof(Node));
printf("结构体开始地址:%p,数据包开始地址:%p:\n",&node,node.data);
return0;
}
可以看出变长数组的数据缓冲区,结构体最后一个成员之后继续来分配内存的。
而使用指针的那种方法,可以看出,指针指向的数据的内存是不连续的。所以不能只用free函数把所有的数据清除。
总结:
变长数组的优点:
变长结构体的内存是连续的,而使用指针的方法的不是,所以变长结构体只需释放一次空间,这样使用起来比较方便。