C语言柔性数组

柔性数组的概念

柔性数组(flexible array member)也叫伸缩性数组成员,这种结构产生与对动态结构体的去求。在平常编程中,有时须要在结构体中存放一个长度是动态的字符串(也多是其余数据类型),通常的作法,实在结构体中定义一个指针成员,这个指针成员指向该字符串所在的动态内存空间。编程

在一般状况下,若是想要高效的利用内存,那么在结构体内部定义静态的数组是很是浪费的行为。其实柔性数组的想法和动态数组的想法是同样的。数组

柔性数组用来在结构体中存放一个长度动态的字符串。网络

普通的方式

其实不用柔性数组咱们同样能够作到:在结构体中定义一个方法,在方法中动态地将指针指向动态数组数据结构

#include <string.h> #include <stdlib.h> typedef struct Test { int a; char *p; } Test; int main() { char *str = (char *)malloc(sizeof(char) * 10); strcpy(str, "hello"); Test *t = (Test *)malloc(sizeof(Test)); t->p = str; printf("%s\n", (t->p)); printf("Address:\n"); printf("t\t %p\n", t); printf("t.a\t %p\n", &(t->a)); printf("t.p\t %p\n", (t->p)); free(t); free(t->p);    //还须要显式的释放p所指的内存
    return 0; }

运行结果:flex

fc7948c3-687d-4d9c-a13a-289c840dc53b

上面的代码的确是能够完成咱们想要的结果。咱们看了一下指针p和数组的起始地址。咱们能够看到动态数组的内存块和字符串的内存是两块不同的内存。spa

可是,咱们在释放空间时,须要显式地释放指针p引用的内存空间,否则会出现内存泄露的状况。操作系统

使用柔性数组的方式

从C99开始便支持了不完整类型实现柔性数组成员。为何使用不完整类型呢?指针

int a[] = {10};

看到这个声明语句,咱们发现a[]其实就是个数组记号,不完整类型,因为赋值语句,因此在编译时便肯定了数组的大小,是一个完整的数组类型。
在结构体中便利用不完整类型在运行对动态的数组进行指明。code

C99标准的定义以下blog

struct Test{ int a; char p[]; // 不仅是char类型,其余类型一样也是能够
}

因为声明内存连续性的关系,柔性数组成员必须定义在结构体的最后一个,而且不能是惟一的成员。
咱们再来看一看整个结构体(包含数组内存的分布状况)

#include <string.h> #include <stdlib.h> typedef struct Test { int a; char p[]; } Test; int main() { Test *t=(Test*)malloc(sizeof(Test)+sizeof(char)*(10+1)); strcpy(t->p,"hello"); printf("%s\n", (t->p)); printf("Address:\n"); printf("t\t %p\n", t); printf("t.a\t %p\n", &(t->a)); printf("t.p\t %p\n", (t->p)); free(t);    //只须要释放一次内存
    return 0; }

再运行结果:

7ee88005-9523-4181-afeb-7c4f29c0c017[4]

由运行结果就能够看出,整个结构体是连续的,而且释放结构体的方式也很是简单直接对结构体指针进行释放。

【注】因为这个是C99的标准,在ISO C和C++的规格说明书中是不容许的。在vs下使用0长度的数组可能会获得一个警告。
然而gcc, clang++预先支持了C99的玩法,因此在Linux下编译无警告

进一步认识柔性数组

现有一个程序

#include<stdio.h> typedef struct _SoftArray{ int len; int array[]; }SoftArray; int main() { int len = 10; printf("The struct's size is %d\n",sizeof(SoftArray)); }

运行结果:

dc83b57f-2795-4d1b-9c2f-8b3655f0ba19

咱们能够看出,_SoftArray结构体的大小是4,显然,在32位操做系统下一个int型变量大小恰好为4,也就说结构体中的数组没有占用内存。为何会没有占用内存,咱们平时用数组时不时都要明确指明数组大小的吗?但这里却能够编译经过呢?这就是咱们常说的动态数组,也就是柔性数组。

先不要乱,让咱们再看一段代码

#include <stdio.h> #include <malloc.h> typedef struct _SoftArray { int len; int array[]; } SoftArray; int main() { int len = 10; SoftArray *p = (SoftArray *)malloc(sizeof(SoftArray) + sizeof(int) * len); printf("After the malloc function the struct's size is %d\n",sizeof(SoftArray)); return 0; }

运行结果:

6c5f8aed-22f2-4852-a3fc-4ca5aa1b8356

是否是有点奇怪,为何申请了内存后结构体大小仍是4呢?

缘由是:动态申请的内存只是申请给数组拓展所用,从上个程序咱们能够看出结构体的大小在建立时已经肯定了,array明确来讲不算是结构体成员,只是挂羊头卖狗肉而已。

下面咱们来看看关于柔性数组的资料:

一、什么是柔性数组?

柔性数组既数组大小待定的数组, C语言中结构体的最后一个元素能够是大小未知的数组,也就是所谓的0长度,因此咱们能够用结构体来建立柔性数组。

二、柔性数组有什么用途 ?

它的主要用途是为了知足须要变长度的结构体,为了解决使用数组时内存的冗余和数组的越界问题。

三、用法:在一个结构体的最后 ,申明一个长度为空的数组,就可使得这个结构体是可变长的。对于编译器来讲,此时长度为0的数组并不占用空间,由于数组名

自己不占空间,它只是一个偏移量, 数组名这个符号自己代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,咱们能够进行动态分配,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是表明了一个偏移量,表明一个不可修改的地址常量!

对于柔性数组的这个特色,很容易构造出变成结构体,如缓冲区,数据包等等:

typedef struct _SoftArray { Int len; int array[]; }SoftArray;

柔性数组用途

    这样的变长数组经常使用于网络通讯中构造不定长数据包,不会浪费空间浪费网络流量,好比我要发送1024字节的数据,若是用定长包,假设定长包的长度为2048,就会浪费1024个字节的空间,也会形成没必要要的流量浪费。

    其实柔性数组成员在实现跳跃表时有它特别的用法,在Redis的SDS数据结构中和跳跃表的实现上,也使用柔性数组成员。

相关文章
相关标签/搜索