柔性数组(结构体成员)

目录

前言: 

柔性数组:

给柔性数组分配空间: 

调整柔性数组大小:

柔性数组的好处: 


前言: 

       柔性数组?可能你从未听说,但是确实有这个概念。听名字,好像就是柔软的数组,是不是意味着这个数组大小是可以变化的?但是不是只有C99才有可变数组吗?别急,往下看(注:此章节涉及动态内存知识,详情请看:动态内存函数-CSDN博客)。

柔性数组:

       柔性数组是在结构体中使用的,就是说可以不指定数组元素内容,但前面必须至少有一个明确大小的数据类型,且柔性数组必须位于结构体中最后一个成员。

       我们分析上面的话可以得到以下四点重要信息:

  1. 必须在结构体中使用。
  2. 柔性数组必须位于结构体中最后一个成员。
  3. 可以不指定其大小。
  4. 前面必须有一个明确大小的数据类型。
//柔性数组
struct S
{
    int n;
    int arr[];//未知大小
};
int main()
{
    struct S s;
    printf("%d\n", sizeof(s));//在计算结构体大小时,不包含柔性数组成员
    return 0;
}

       因为柔性数组没有定义大小,而且柔性数组必须位于结构体的最后一个成员,所以在计算内存的时候,默认把柔性数组的大小计为0。既然没有计算柔性数组的大小,那么到底该如何使用呢?

给柔性数组分配空间: 

       此时就需要用到动态内存函数了,因为结构体大小固定,所以我们想使用柔性数组,就必须给结构体分配空间,所以,结构体的空间也需要动态内存函数来开辟(以至于我们要使用结构体指针)

//柔性数组
struct S
{
    int n;
    int arr[];//未知大小
};
int main()
{
    struct S s;
    struct S* p =(struct S*) malloc(sizeof(struct S) + 5 * sizeof(int));
    //开辟原来结构体大小,之后再给柔性数组分配空间为5个int类型
    p->n = 100;//柔性数组
struct S
{
    int n;
    int arr[];//未知大小
};
int main()
{
    struct S s;
    struct S* p = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
    //开辟原来结构体大小,之后再给柔性数组分配空间为5个int类型
    p->n = 100;
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        p->arr[i] = i;
    }

    //打印
    printf("%d\n", p->n);
    for (i = 0; i < 5; i++)
    {
        printf("%d ", p->arr[i]);
    }
    //释放
    free(p);
    p = NULL;
    return 0;
}
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        p->arr[i] = i;
    }

    //释放
    free(p);
    p = NULL;
    return 0;
}

       堆区中开辟一块动态内存,并使用p来指向这块动态内存。这块动态内存的大小必须大于结构体大小,柔性数组必须配合动态内存函数使用,因为柔性数组没有办法直接赋值,我们只能配合动态内存函数来对柔性数组赋值。 

       一定注意,我们申请的内存空间也包括了结构体中的首个元素。 

调整柔性数组大小:

       使用realloc函数调整其大小。

//柔性数组
struct S
{
    int n;
    int arr[];//未知大小
    //int arr[0];//也可以这样定义
};
int main()
{
    struct S s;
    struct S* p =(struct S*) malloc(sizeof(struct S) + 5 * sizeof(int));
    p->n = 100;
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        p->arr[i] = i;
    }
    struct S*ptr=(struct S*)realloc(p, 44);
    //将总体大小调整为44字节
    //相当于给柔性数组扩容为40字节    

    if (ptr != NULL)
    {
        p = ptr;
    }
    for (i = 0; i < 10; i++)
    {
        p->arr[i] = i;
    }
    for (i = 0; i < 10; i++)
    {
        printf("%d ", p->arr[i]);
    }
    //释放空间
    free(p);
    p = NULL;
    return 0;
}

柔性数组的好处: 

       既然指针指向的空间需要用动态内存函数开辟,那么直接将柔性数组替换为指针不就好了吗?干嘛多此一举,这么费事?此时我就举一个不用柔性数组的例子:

struct S
{
    int n;
    int* arr;
};
int main()
{
    struct S* ps = (struct S*)malloc(sizeof(struct S));
    ps->arr = malloc(5 * sizeof(int));
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        ps->arr[i] = i;
    }
    for (i = 0; i < 5; i++)
    {
        printf("%d ",ps->arr[i]);
    }//调整大小
    int* ptr = realloc(ps->arr, 10 * sizeof(int));
    if (ptr != NULL)
    {
        ps->arr = ptr;
    }
    for (i = 5; i < 10; i++)
    {
        ps->arr[i] = i;
    }
    for (i = 0; i < 10; i++)
    {
        printf("%d ", ps->arr[i]);
    }
    free(ps->arr);
    ps->arr=NULL;
    free(ps);
    ps = NULL;
    return 0;
}

        有人说,为啥要定义结构体指针呢?以至于还要给结构体开辟空间。大家有没有想过,我们平时使用函数难免会传参,我们知道形参是实参的一份临时拷贝,所以为了节省空间,我们一般是传址调用所以这里使用了结构体指针开辟内存。

       之后来看使用柔性数组完成以上相同功能:

struct S
{
    int n;
    int arr[];
};
int main()
{
    struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
    
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        ps->arr[i] = i;
    }
    for (i = 0; i < 5; i++)
    {
        printf("%d ", ps->arr[i]);
    }
    printf("\n");
    //调整大小
    int* ptr = realloc(ps, 11 * sizeof(int));

    if (ptr != NULL)
    {
        ps = ptr;
    }
    for (i = 5; i < 10; i++)
    {
        ps->arr[i] = i;
    }
    for (i = 0; i < 10; i++)
    {
        printf("%d ", ps->arr[i]);
    }

    free(ps);
    ps = NULL;
    return 0;
}

       此时我们就会发现,不使用柔性数组需要释放两次由动态内存函数开辟的空间(因为还要释放结构体成员指针开辟的空间),会显得有些繁琐;而柔性数组就不需要释放两次,只需要一次即可满足需求。这就是柔性数组的好处。

       有利于访问速度的提升:因为动态内存开辟是连续的,所以就提高了访问速度,也有利于减少内存碎片。

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值