C语言——伸缩型数组成员

       最近了解到TLV协议后,开始了对其的代码实现,并在期间发现了伸缩性数组这个眼熟却手生的东东,借此机会深挖一下这个伸缩型数组成员(flexible array member)。

struct TLV_BODY 			 // TLV报文
{
	short tag;         	     // value类型
    short value_length; 	 // 报文长度
    char  value[0];     	 // 数据内容
};

注:这个char value[0]; 便是伸缩型数组成员的声明!

1、基本简介:

       伸缩型数组成员是在C99标准中新增的一个特性。如果某个结构体含有此特性,那么其最后一个数组成员会具有一些特性:

  • 该成员数组不会立刻存在(程序运行时,不会立即为其分配内存空间)
  • 程序猿可以利用其创建数目为指定个数的数组

接下来,我们进一步来学习如何使用该数组成员(详情请参考C primer plus 章节14.7.9)。

首先,正确声明一个伸缩型数组成员需要满足以下几条规则:

       ①伸缩型数组成员必须是结构体的最后一个成员

       ②结构体中,必须有且至少有一个成员

       ③声明方法类似于普通函数,只不过它的方括号中不用指定数组元素个数,一般设置为空或0

下面举例说明:

struct var
{
	int			i;
	float		j;
	double		arr[0];		//伸缩型数组成员
    //double	arr[];		//这样声明也可以
};

       声明一个struct var类型的结构体变量时,不能用数组arr[]做任何事,因为系统并没有给该数组分配存储空间。事实上,这和在C99中引入该特性的初衷有关。它并不是让你声明一个struct var类型的结构体变量,而是希望你声明一个指向struct var类型的指针,然后调用malloc()函数来为这个伸缩型数组成员动态分配足够的空间,以存储struct var类型结构体中其他内容和伸缩性数组成员所需的额外存储空间!

例如,我们可以:

struct var		*ptr;

ptr = malloc(sizeof(struct var) + 5 * sizeof(double));

       这样我们就为结构体的其他内容以及伸缩型数组成员申请了足够的内存,来存储相关数据,并且可以通过指针ptr来访问这些成员。

ptr->i = 15;
ptr->j = 15.6
ptr->arr[4] = 18.5;
2、程序演示

下面以一个具体的程序来演示如何使用伸缩型数组成员。

flex_arr.c 程序代码如下:

#include <stdio.h>
#include <stdlib.h>

struct arr
{
	int 	count;
	double 		average;
	double 		scores[]; 			//伸缩型数组成员
};

void show_arr(const struct arr *p);	//不改变结构体中的内容,故使用关键字const

int main (int argc, char *argv[])
{
    int 			total = 0;
    int				n = 5;
    int 			i;
    struct arr 	   *p1;

    //为结构体分配存储空间
    p1 = malloc(sizeof(struct arr) + n * sizeof(double));

	p1->count = n;
    for (i = 0; i < n; i++)
    {
    	p1->scores[i] = 20.0 - i;
    	total += p1->scores[i];
    }
    p1->average = total / n;
    show_arr(pl);
	
	//释放在堆中动态分配的存储空间
	free(p1);	

    return 0; 
}

void show_arr(const struct arr *p)
{
	int i;

    printf ("Scores : ");
    for (i = 0; i < p->count; i++)
    {
    	printf("%g ", p->scores[i]);
    }
    
    printf ("\n");
    printf ("Average: %g\n", p->average) ;
}



运行结果:
在这里插入图片描述

3、补充

       对于含有伸缩型数组成员的结构体有一些特殊的处理要求!故在编程时请注意以下三点:
       第一、不能用结构体(含有伸缩型数组成员的结构体)进行赋值或copy;

struct var		*p1;
struct var		*p2;
...
*p1 = *p2;		//	不要这样做!

采取这种方法只能拷贝除伸缩型数组成员以外的其他成员。如果要对伸缩型数组成员进行copy的话,可以使用memcpy()函数。

       第二、不要以按值方式把这种结构体传递给其他结构体(传值调用)。原因相同,按值传递一个参数与赋值类似。要把结构的地址传递给函数。

       第三、不要使用带伸缩型数组成员的结构体作为数组成员或另一个结构体的成员(结构体嵌套)。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值