C语言中的柔性数组

  在讲述柔性数组成员之前,首先要介绍一下不完整类型(incomplete type)。不完整类型是这样一种类型,它缺乏足够的信息例如长度去描述一个完整的对象,它的出现反映了C程序员对精炼代码的极致追求,这种代码结构产生于对动态结构体的需求。
  鉴于这种代码结构所产生的重要作用,C99甚至把它收入了标准中。C99使用不完整类型实现柔性数组成员,在C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组(flexible array)成员(也叫伸缩性数组成员),但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。柔性数组成员只作为一个符号地址存在,而且必须是结构体的最后一个成员,sizeof 返回的这种结构大小不包括柔性数组的内存(即:sizeof(SoftArray)=4)。柔性数组成员不仅可以用于字符数组,还可以是元素为其它类型的数组。包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。柔性数组的使用请看下面柔性数组的定义:
  

typedef struct _soft_array
{
    int len;
    int array[0];
}SoftArray;

有些编译器会报错无法编译可以改成:

typedef struct _soft_array
{
    int len;
    int array[];
}SoftArray;

下面是柔性数组的完整示例:

#include 
#include 

typedef struct _soft_array
{
    int len;
    int array[];
}SoftArray;

SoftArray* create_soft_array(int size)
{
    SoftArray* ret = NULL;

    if( size > 0 )
    {
        ret = (SoftArray*)malloc(sizeof(*ret) + sizeof(*(ret->array)) * size);

        ret->len = size;
    }

    return ret;
}

void fac(SoftArray* sa)
{
    int i = 0;

    if( NULL != sa )
    {
        if( 1 == sa->len )
        {
           sa->array[0] = 1;
        }
        else 
        {
            sa->array[0] = 1;
            sa->array[1] = 1;

            for(i=2; ilen; i++)
            {
                sa->array[i] = sa->array[i-1] + sa->array[i-2];
            }
        }
    } 
}

void delete_soft_array(SoftArray* sa)
{
    free(sa);
}

int main()
{
    int i = 0;
    SoftArray* sa = create_soft_array(10);

    fac(sa);

    for(i=0; ilen; i++)
    {
        printf("%d\n", sa->array[i]);
    }

    delete_soft_array(sa);

    return 0;
}

如下为关于柔性数组的一道面试题

对以下数据结构中data的处理方式描述正确的是()
struct Node
{
   int size;
   char data[0];
};

A data将会被编译成一个char *类型指针
B 全部描述都不正确
C 编译器会认为这就是一个长度为0的数组,而且会支持对于数组data的越界访问
D 编译器会默认将数组data的长度设置为1

正确答案: C

  
很多人其实会有这种疑惑,就是为什么不用指针去代替变长结构体,比如:

structNode
{
   int size;
   char* data;
};

就这个问题,我总结了一下用指针和用变长结构体的区别:
1.在位置方面:指针可以放在任何地方,但是变长结构体的变长部分一定要放在结构体的最后。

2.在内存占用方面:指针会占一个指针的大小的内存空间,但是变长数组是不占内存的,它只是一个占位符。

3.在内存布局方面:指针指向的内存和结构体的内存可以是不连续的,但是变长部分和结构体的内存必须是连续。

4.在内存释放方面:使用指针,就要先释放指针所指的内存在释放整个结构体的内存,否则会照成内存泄露。但是使用变长结构体直接释放整个结构体的空间就可以了。

5.一个限制:指针可以用在C++的类中,但是变长结构体就不可以了。因为有些编译器会将一些额外的信息放在类的最后,比如vptr或者虚基类的内容,使用了变长的类,就会把这部分的值改变,这种行为是未定义的,谁也不知道会发生什么。

你可能感兴趣的:(C)