在这里我们来说说C语言中遇到的柔性数组,为了能够更好的让读者理解柔性数组,在了解柔性数组之前我们先通过理解不完整类型来引入柔性数组的概念。在此之前应该没有那本数会完整的介绍不完整类型,所以大家读到不完整类型的时候都会感觉到脑空白一片,但其实我们在程序中会经常遇到不完整类型,下面我们举例来说明什么是柔性数组。
1、不完整类型:
很多工程中经常会使用到不完整类型,例如:
struct Test;
void Move(int,int);
extern int a[];
a[]、void Move(int,int)和Test在这里只给出了声明并没有给出定义,不完整类型必须通过某些方式补充完整之后才能使用它进行定义变量,否则只能用于定义指针或引用。上面的三种情况分别是对结构体、函数、数组的进行了声明,如果我们通过函数来调用的话就像下面这样:
#include<stdio.h>
struct Test;
void Move(int,int);
extern int a[];
int main()
{
Test pt;
Move(3,2);
a[0] = 2;
return 0;
}
如果这样写,只进行编译不进行链接的时候,不会报错,如果程序进行链接或者运行的时候就会出错,因为代码在上面只进行了声明,相当于告诉编译器这些类型是存在的,但具体类型是什么我也不知道,编译器无需知道具体的定义类型是什么,只需要知道这个类型存在就行,在执行的时候,就必须定义出类型的真实部分,让程序可以找到声明的类型主体,知道怎么执行,这就是为什么编译不会报错而执行会报错的原因。上面的三种例子就是不完整类型。接下来我们来看看柔性数据具体是什么东东。
2、柔性数组成员:
柔性数组成员也叫伸缩性数组成员,在平时的变成中会在结构体中放一个动态变化的字符串,下面我们来看看代码是怎么实现的:
#include<stdio.h>
struct Test
{
int a;
float b;
char *pc;
};
int main()
{
char *sr = "hello world!";
Test t;
t.pc = sr;
printf("%s\n",t.pc);
return 0;
}
代码这样写虽然可以通过结构体中的字符串指针对指针sr所指向的字符串进行管理,但这种做法会造成两种不良影响,一是字符串本身和所管理的结构体分离,不利于操作,二是pc指针策划年港元要占用相应的空间,如果能把字符串跟结构体直接连接在一起进行操作,并且想办法让结构的空间尽可能的小,那样更好,我们修改代码:
#include<stdio.h>
#include<string.h>
#include<malloc.h>
struct Test
{
int a;
float b;
char *pc;
};
int main()
{
char sr[] = "hello world!";
Test *ptm = (Test*)malloc(sizeof(Test)+strlen(sr)+1);//这里的ptm是一个结构体指针类型变量,给它申请了结构体空间个多余的字符串存储空间
strcpy(((char*)(ptm+1)),sr);//这里的ptm+1刚好跳出Test结构体空间,在经过强转为字符行的指针来复制存储sr只想空间的内容;
printf("%s\n",(char*)(ptm+1));
return 0;
}
这样,(char*)(pt+1)就是字符串“hello world!”的地址,这时候结构体中的pc成员成了多余的东西,可以直接去掉,不过会产生另外一个问题就是(char*)(pt+1)表示字符串多少不美观,也不太方便,如果找一种方法既能直接引用该字符串,有不占用结构体空间那该多好,符合这种条件的代码结构应该是一个非常的符号地址,在结构体尾部防止一个长度为0的数组是一个绝妙的解决方案。就像下面:
#include<stdio.h>
#include<string.h>
#include<malloc.h>
struct Test
{
int a;
float b;
char pc[0];
};
int main()
{
char sr[] = "hello world!";
Test t;
memcpy(t.pc,sr,sizeof(sr));//重点
printf("%s\n",t.pc);//因为pc[0]刚好是结构体最后一个成员,也刚好是main函数中sr的首地址,下面(3)描述的就是这个问题
return 0;
}
柔性数组的关键所在:
(1)必须是结构体最后一个成员,而且结构体中只能有一个;
(2)柔性数组成员不占空间;
(3)柔性数组成员所管理的字符串一定是在栈区,并且位置刚好位与结构体变量的下方,这样才能保证不占用空间的字符符号刚好就是字符串的首地址;
(4)之所以被称作柔性数组成员,其柔性变现为所管理的字符串长度可以动态变化,而无需对所管理的结构体进行修改,成员特性表现为这种方式的定义一定只能以成员方式出现在结构体中。