从零开始了解“柔性数组”

首先我们来看一道面试题
如果你还不能很快就得出答案,那可以通过本次的介绍彻底的了解一下 “柔性数组”
参考答案会在文末给出哦!

开发C代码时,经常见到如下类型的结构体定义:

typedef struct list_t{
struct list_t *next;
struct list_t *prev;
char data[0];
}list_t;

最后一行char data[0];的作用是()

A、方便管理内存缓冲区

B、减少内存碎片化

C、标识结构体结束

D、没有作用

柔性数组是C99引入的一个新特性
这个特性允许你在定义结构体的时候创建一个空数组,而这个数组的大小可以在程序运行的过程中根据你的需求进行更改
特别注意的一点是:这个空数组必须声明为结构体的最后一个成员,并且还要求这样的结构体至少包含一个其他类型的成员
上面的简答介绍可能还是没能足够让你了解什么是“柔性数组”,以及具体又该如何使用,下面就通过具体的例子进行解释:

现在我们需要进行学生的一些基本信息的统计,假设我们定义了如下的一个结构体:

typedef struct
{
  int stuID;
  int name;
  char address[30];
}ST_STU_INFO;

可以看到在最后存储“地址(address)“的结构体中,我们申请了一个30个字节的数组,如果我们存储的时候只存入较短的地址以上的定义的是没问题的,但需要存入的地址信息超出了30个字节,程序很可能就崩掉了,就像下面这样

这时候具有主角光环的柔性数组就可以登场啦!
我们在结构体中定义一个柔性数组,这样可以确保能够在程序运行过程中“动态”的进行结构体的扩展,好像是有点动态的感觉了呀!
具体代码如下:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//存放学生信息结构体
typedef struct{
    int stuID;
    int age;
    char address[];
}ST_STU_INFO,*pStuInfo;

//为结构体分配内存
pStuInfo ComposeStuInfo( int stuID,int age, const char *paddress)
{
    pStuInfo ptmpInfo = malloc(sizeof(*ptmpInfo) + sizeof(char) * strlen(paddress) + 1);
    if(ptmpInfo != NULL){
        ptmpInfo->stuID = stuID;
        ptmpInfo->age = age;
        strcpy(ptmpInfo->address, paddress);
    }
    return ptmpInfo;
}

// 打印学生信息
void printStuInfo(pStuInfo ptmpInfo)
{
    printf("stuID : %d   age : %d   Address: %s\nSize of Struct:%d\n\n",
            ptmpInfo->stuID,ptmpInfo->age,ptmpInfo->address,sizeof(*ptmpInfo));
}

//主程序
int main()
{
    pStuInfo CodeLab = ComposeStuInfo(100013,20, "Tencent Building, Central District, High-tech Park, Nanshan District, Shenzhen");
    if(CodeLab != NULL){
        printStuInfo(CodeLab);
        free(CodeLab);
    }
    pStuInfo subCodeLab = ComposeStuInfo(200013,23, "Tencent Building");//Tencent Building里面的大佬个个都很厉害吧~~~
    if(subCodeLab != NULL){
        printStuInfo(subCodeLab);
        free(subCodeLab);
    }
    return 0;
}

运行之后得到结果如下:

stuID : 100013   age : 20   Address: Tencent Building, Central District, High-tech Park, Nanshan District, Shenzhen
Size of Struct:8

stuID : 200013   age : 23   Address: Tencent Building
Size of Struct:8

从结果输出可以看到,我们成功使用了不同长度的地址,当然程序也不会出现文章开头那样崩溃的情况

此外,虽然我们对结构体进行了如下的初始化

pStuInfo ptmpInfo = malloc(sizeof(*ptmpInfo) + sizeof(char) * strlen(paddress) + 1);

但是却在输出中可以看到结构体的大小并没有因此而发生变化Size of Struct:8

ST_STU_INFO结构体的大小是8, 两个int型变量大小刚好为8,也就是说结构体中的数组并没有占用内存

针对柔性数组这一不占用内存的特性,可以构造出内存缓冲区,同时由于是使用多少就申请多少,也起到了减少内存碎片化的作用,所以文章开头的面试题答案是AB

而对于选项C而言,恰恰相反的是,柔性数组并不是标识结构体结束,而是作为结构体的一种拓展

同时也可以理解为柔性数组为结构体的一个偏移地址,这使得结构体的大小可以进行动态的变化

最后可能还是会有疑问,这和直接使用指针有啥区别呢?

typedef struct{
    int stuID;
    int age;
    char *pAddress;
}ST_STU_INFO;

首先柔性数组不占用内存,而指针则不然,此外柔性数组在使用上是直接访问,形式上更加直观,而指针需要经过声明再进行动态分配内存,在效率上和柔性数组相比也稍微低一些

Linux内核代码中有较多的柔性数组的使用,如果想再深入的了解可以在 跳表(Skip List) 的实现中加以运用

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值