共计 1748 个字符,预计需要花费 5 分钟才能阅读完成。
一 历史
在 c99 标准出来之前。如果要在某个结构体中使用字符串变时,为了使字符串变量存储地址能与结构体整体连在一起,需要这样实现
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct pen
{
int len;
char *data;// 字符串变量
}pen;
int main(int argc, char **argv)
{
char str[] = “this is a string”;// 需要填入的字符串
/*
动态申请一个 pen 类型结构体变量,
它的大小为,pen 类型的本身长度,
再加上 str(需要填入字符串的长度), 再加 1,
*/
struct pen *p = (struct pen*)malloc(sizeof(pen) + strlen(str) + 1);
p->data= NULL;
// 设置 p 的长度为目标字符串的长度
p->len = strlen(str);
/*
将目标字符串拷贝到结构体对应的位置
此处为什么 p + 1 之后指向的是 pen 结构体存储空间后的位置,而不是只加一呢?
因为此处的 p + 1 偏移的是 p 指向类型大小的偏移量,什么意思呢?p 指向的类型为 pen 类型的结构体,
而 pen 类型的结构体大小为 len(4 字节)加上 data(8 个字节),由于此处有内存对齐的情况,
所以实际上 pen 大小为 4 + 8 + 4(这个 4 为内存对齐的多余空间,如果再增加一个 int 类型的变量,
pen 的大小还是为 16)=16 字节
所以此处 p + 1 向后偏移了 16 字节,通过下方地址打印可以详细看出
*/
strcpy((char*)(p + 1), str);
//int 所占字节数,不同机器不同。一般 64 位为 4 字节
printf(“sizeof(int): %ld\n”, sizeof(int));
// 上文已说明,16 字节
printf(“sizeof(pen): %ld\n”, sizeof(pen));
// 起始地址
printf(“start: %p\n\n”, (char*)p);
// 上文已说明,偏移后的地址
printf(“(p+1) : %p\n”, (char*)(p+1));
// 偏移后,对应的字符串
printf(“(char*)(p+1): %s\n\n”, (char*)(p+1));
// 结构体变量 data 的地址
printf(“&(p->data): %p\n”, &(p->data));
// 数据,null,此处为空,故此变量已经被浪费。访问对应字符串数据需要(char *)(p+1)
printf(“p->data: %s\n\n”, p->data);
}
二 柔性数组
通过上文我们可以看到,data 字段是一个被浪费的指针(8 个字节)。并且我们想取到结构体下的字符串变量时需要 (char *)(p+1) 写这么一串东西,既不好看,也容易出错,那有没有可以直接用 p ->data 取到字符串并且内存是连续的,而且又不浪费 data 字段呢,柔性数组 就是用来干这个的。
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct pen
{
int len;
char data[];// 柔性数组
}pen;
int main(int argc, char **argv)
{
char str[] = “this is a new string”;// 需要填入的字符串
struct pen *p = (struct pen*)malloc(sizeof(pen) + strlen(str) + 1);
p->data= NULL;
p->len = strlen(str);
strcpy((char *)(p+1), str);
printf(“pen->data: %s\n”, p->data);
}
C99 使用不完整类型实现柔性数组成员,在 C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组 (flexible array) 成员(也叫伸缩性数组成员),但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。柔性数组成员只作为一个符号地址存在,而且必须是结构体的最后一个成员,sizeof 返回的这种结构大小不包括柔性数组的内存(此段话摘自:https://blog.csdn.net/ce123_z…)