c++柔性数组

背景讨论

在日常编程中,可能需要在结构体中存放一个长度动态变化的变量(这里统一以字符变量为例子),一般做法是在结构体中定义一个字符指针。

1
2
3
4
5
6
typedef struct test    
{
int a;
double b;
char *p;
}test;

首先了,这种做法造成了字符串p的存储空间和结构体是分离,如果想把它们连在一起,可以通过如下方式:

1
2
3
char a[] = "Hello\n";
test * t = (test *)malloc(sizeof(test) + strlen(a) + 1);
strcpy(t + 1,a);

通过上述代码的定义,(char *)(t + 1)就是字符串“Hello\n”的首地址了。但是这个时候p就变的有点多余并且还要占用4个字节的空间。正是出于这样的一个考虑,c99加入了柔性数组的这样一个属性。

柔性数组的介绍

c99中,结构体的最后一个字段允许是一个未知大小的数组,这个数组就叫柔性数组。结构体的柔性数组前必须包含一个其他成员。

柔性数组成员只作为一个符号地址存在,而且必须是结构体的最后一个成员,sizeof返回的这种结构大小不包括柔性数组的内存。

例如:

1
2
3
4
5
6
typedef struct test  
{
int a;
double b;
char c[]; //或者声明为:char c[0],但是这种形式,有些编译器会报错无法编译。
};

使用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <cstring>
#include <string>
using namespace std;

struct test
{
int a;
double b;
char c[0];
};
int main(){
cout << "test的大小:"<<sizeof(test) << endl;
test * t = (test * )malloc(sizeof(test) + 10 * sizeof(char));
strcpy(t->c,"Hello");
cout << t->c << endl;
free(t);
return 0;
}

上述代码的输出:

1
2
test的大小:16
Hello

所以从输出结果可以知道,首先,c不占结构体的内存,然后t->c就是“hello world”的首地址,不需要再使用( char * )( t + 1 )这么复杂代码了.