柔性数组
柔性数组,简而言之就是一个在struct结构里的标识占位符(不占结构struct的空间),只能在堆上生成。
在结构体内,有一个数组,必须是结构体中的最后一个元素,而且有特定的形式[]或者[0],结构体中至少要有两个成员体变量。
实例:
此时的字符数组 name 是不占空间的。
柔性数组的应用实例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct data
{
int len; //一般用来表示字符数组的字符个数
char name[];
}S;
int main(void)
{
S s;
printf("sizeof(s)=%d\n",sizeof(s));
int len = 10; //申请空间
struct data *p =(struct data*)malloc(sizeof(s)+sizeof(char)*len);
//判断是否申请成功&请空处理
p->len = len;
strcpy(p->name,"helloqpy");
printf("%s\n",p->name);
//释放指针p
free(p);
return 0;
}
程序运行结果:
这样子我们就有疑问,柔性数组到底方便在哪里了?每次使用它还要申请堆内存,我们直接在结构体里面放一个字符串指针,然后给这个指针再malloc分配一下内存不就好了么?
如下面代码:
但是注意:此时的len和字符串指针是一块存储的 但是结构体里面的字符串 也就是helloqpy和我们的结构体是分开的 ,其存储的位置在指针存储。
那么我们为什么要使用柔性数组??
是因为我们想给一个结构体内的数据分配一个连续的内存!这样做的意义有两个好处:
第一个意义是,方便内存释放。如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。(读到这里,你一定会觉得C++的封闭中的析构函数会让这事容易和干净很多)
第二个原因是,这样有利于访问速度。连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)
使用柔性数组实现斐波那契数列
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct data
{
int n; //表示数列的项数
int arr[];//柔性数组
}S;
//遍历斐波那契数列的函数
void show_arr(struct data *p_str)
{
int i=0;
for(i=0;i<p_str->n;i++)
//注意此处是p_str->n,而不是len 要看传进来的参数
{
printf("第(%d)项arr[%d]=%d\n",(i+1),i,p_str->arr[i]);
}
}
//生成斐波那契数列的函数
void create_arr(int len)
{
struct data *p_str = (struct data *)malloc(sizeof(struct data)+sizeof(int)*len);
p_str->n = len;
//循环赋值
int i = 0;
for(i=0;i<len;i++)
{
if(i<=1) //arr[0]和arr[1]是第一项和第二项是1
p_str->arr[i] =1;
else if(i>=2)
{
//后面的是前两项的和
p_str->arr[i] = p_str->arr[i-1] + p_str->arr[i-2];
}
}
//调用遍历函数
show_arr(p_str);
free(p_str);
}
int main(void)
{
int len = 10;
//调用生成数列的函数即可
create_arr(len);
return 0;
}
函数实现效果如下: