1 柔型数组的概念
引自<http://blog.chinaunix.net/uid-27122224-id-3308027.html>
结构中最后一个元素允许是未知大小的数组,这个数组就是柔性数组。
但结构中的柔性数组前面必须至少一个其他成员,柔性数组成员允许结构中包含一个大小可变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。包含柔数组成员的结构用malloc函数进行内存的动态分配,且分配的内存应该大于结构的大小以适应柔性数组的预期大小。柔性数组到底如何使用?
例子:
typedef struct st_type
{
int i;
int a[0];
}type_a;
有些编译器报错无法编译可改成:
typedef struct st_type
{
int i;
int a[];
}type_a;
这样,我们定义一个可变长的结构体,用sizeof(type_a)得到的只有4,就是sizeof(i) = sizeof(int). 那个0元素的数组没有占用空间,而后我们就可以进行变长操作了。通过如下表达式结构体分配内存:
type_a *p = (type_a*)malloc(sizeof(type_a) + 50*sizeof(int));
在结构中,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;
}
输出结果:
Size of MyData: 4
myData's Data is: 123456789
2 柔性数组的使用
C99使用不完整类型实现柔性数组成员,标准形式是这样的
struct s_test
{
int a;
double b;
char c[];
};
c同样不占用test的空间,只作为一个符号地址存在,而且必须是结构体的最后一个成员。柔性数组成员不仅可以用于字符数组,还可以是元素为其它类型的数组,例如:
struct s_test
{
int a;
double b;
float[];
};
应当尽量使用标准形式,在非C99的场合,可以使用指针方法。有些人使用char c[1],这是非常不可取的,把这样的a用作柔性数组成员会发生越界行为,虽然C/C++标准并没有规定编译器应当检查越界,但也没有规定不能检查越界,为了一个小小的指针空间而牺牲移植性,是不值得的。
#include <iostream>
#include <malloc.h>
using namespace std;
typedef struct s_test
{
int i;
double b;
char ch[0]; // or char ch[];
}st, *pst;
int main()
{
char ch1[] = "Hello world!";
char ch2[] = "This is a test,i love Arsenal!";
pst pstest1 = (s_test*)malloc(sizeof(s_test) + strlen(ch1) + 1);
if (NULL != pstest1)
{
pstest1->i = 1;
pstest1->b = 11;
strcpy_s(pstest1->ch, strlen(ch1) + 1, ch1);
}
cout << "pstest1: "
<< pstest1->i << " " << pstest1->b
<< " " << pstest1->ch << endl;
pst pstest2 = (pst)malloc(sizeof(st) + strlen(ch2) + 1);
if (NULL != pstest2)
{
pstest2->i = 2;
pstest2->b = 22;
strcpy_s(pstest2->ch,strlen(ch2)+1, ch2);
}
cout << "pstest2: "
<< pstest2->i << " " << pstest2->b
<< " " << pstest2->ch << endl;
free(pstest1);
free(pstest2);
system("pause");
return 0;
}
运行结果:
pstest1: 1 11 Hello world!
pstest2: 2 22 This is a test,i love Arsenal!
请按任意键继续. . .
而构造缓冲区就是方便管理内存缓冲区,减少内存碎片化,它的作用不是标志结构体的结束,而是扩展。
样的变长数组常用于网络通信中构造不定长数据包,不会浪费空间浪费网络流量,比如我要发送1024字节的数据,如果用定长包,假设定长包的长度为2048,就会浪费1024个字节的空间,也会造成不必要的流量浪费