柔型数组

本文详细介绍了柔性数组的概念及其在C99标准中的应用。柔性数组允许结构体包含一个大小可变的数组,使得结构体能够在运行时动态调整其大小。文章通过实例展示了如何使用柔性数组进行内存分配,并解释了其在网络通信等场景中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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!
请按任意键继续. . .


对于0场数组的这个特点,很容易构造出编程结构体,如缓冲区、数据包等;
而构造缓冲区就是方便管理内存缓冲区,减少内存碎片化,它的作用不是标志结构体的结束,而是扩展。
样的变长数组常用于网络通信中构造不定长数据包,不会浪费空间浪费网络流量,比如我要发送1024字节的数据,如果用定长包,假设定长包的长度为2048,就会浪费1024个字节的空间,也会造成不必要的流量浪费


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值