自制编程语言2.1柔性数组

柔性数组是c99中的玩意,在c89中并没有,起初柔性数组叫做柔性数组成员(flexible array memeber),因为它必须要放在一个结构体中作为结构体成员存在,下面介绍它的来头。

看似功能简单的语言,往往更底层,且更灵活,受限制较少,在自由发挥之下往往可以碾压那些高级语言,比如汇编和C就是创造力无限的两种语言,就像盖房子,底层语言给用户提供的是原材料,比较累但是想盖啥样的房子都行,高级语言提供的是房子的结构,它只需要小部分工作,房子就成型了,因此盖房子更快,但是风格也相对单一,就拿c语言来说他可是开发linux内核的语言,不过linux说没有采用c++是因为好的c++程序员很少,c程序员才是对代码精炼的极致追求者,这也正是柔性数组诞生的原因,在结构体汇总经常需要单独存储一个字符串,由于字符串的长度不固定,一种较为常见的做法是在结构体中加一个指针作为结构体成员,用该指针指向字符串,举个例子,假设结构体是从堆中动态分配的,这和咱们编译器中的应用更接近,见下面

<code>struct sample{ int length; char* str; } struct sample * s = malloc(sizeof(struct sample)) s->length=10; s->str = malloc(s.length+1) strcpy(s->str,"abcdefghij",10) s->str[s->length] = '\0'/<code>

功能实现了,此方法完全可以胜任,但是这样一来,字符串str占用的内存和结构体s本身还是分离的,而且字符串需要额外维护一个用malloc申请的动态内存,因此c程序员认为还可能有优化的地方,如果当字符串本身就位于struct中不是更好吗,你也想到了,在struct的末尾放一个数组就行了,此数组专门用来存储字符串,但是我们是想让结构体存储不同长度的字符串,可是字符串长度若不是固定的话,结构体的长度也就不固定了,编译器需要在编译的时候就确定出数据类型,的主要目的就是确定该数据类型的长度,就是内存大小,因此不同的长度就等于定义了多种不同给的数据类型,我们不能为每种长度的字符串单独建一个struct吧,因此为了使得结构体长度固定,位于结构体中的数组的长度应该为0.把结构体改为一以下代码。

<code>struct sample{ int length; char str[0]; } char* string = "abcdefghij"; int lengt = strlen(string); struct sample* s=malloc(sizeof(struct sample)+length+1) s->length=length+1; strcpy(s->str,string,length); s->str[s->length] = '\0';/<code>

见第三行,尽管数组str的长度为0,但是后面8-10行我们把它当成包括实际字符串长度的数组来运用,这UIran会涉及越界,但是只要做好边界控制就可以,其内存布局如图


其中灰色的部分便是结构体struct sample原本的大小;

但是c标准规定不能定义0长度的数组,所以有些编译器就把0长度的数组作为自己的非标准扩展,毕竟得民心者得天下,GCC就支持此类型数组,鉴于标准是来自用户的合理需求,较新的C99就收录了此标准,它使用不完整的类型来实现此需求,因此柔性数组成员被扶正了C99规定,柔性数组成员在结构体中只以符号地址的身份存在,并且一定是结构体的最后一个成员,以上结构体在C99中如下展示。

<code>struct sample{ int length; char str[]; };/<code>

str数组名后[]并没有元素个数,因此str只作为符号地址存在与结构体中,提醒一下,尽管这里是用字符举例,但任何类型都可以用于柔性数组成员。

over