【C】柔性数组@动态内存管理

简介: 柔性数组

@TOC
:key:引:

也许你从来没有听说过 柔性数组(flexible array)这个概念,但是它确实是存在的。
C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。

要让数组大小可大可小可控,就要配合动态内存开辟。

例如:

struct st_type
{
    int i;
    int a[0];//未知大小--不过是允许写成0
};

如果在有些编译器上报错,就改成:

struct st_type
{
    int i;
    int a[];//未知大小
};

5.1 柔性数组的特点

:snowflake:1. 结构中柔性数组成员 前面必须 至少一个其他成员
:snowflake:2. sizeof 返回的 包含柔性数组成员的这种结构大小,不包含柔型数组内存(也存在着内存对齐)。

上代码感受:

#include<stdio.h>

struct st_type
{
    int i;//4byte
    int a[];
};

int main()
{
    printf("%d\n", sizeof(struct st_type));
    return 0;
}

运行结果:
在这里插入图片描述

:snowflake:3. 包含柔性数组成员的结构要用 malloc进行动态内存分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

下面就来介绍柔性数组的使用。

5.2 柔型数组的使用

:snowflake: 包含柔型数组成员的结构体使用,要 配合 malloc这样的动态内存分配函数。

在这里插入图片描述
:snowman:为包含柔性数组成员的结构动态申请空间:

struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type) + 10 *sizeof(int));

:snowman:若数组空间不够,希望调整为20个int

struct st_type* ptr = (struct st_type*)realloc(ps ,sizeof(struct st_type) + 20 * sizeof(int));

上完整代码感受:

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

struct st_type
{
    int i;//4byte
    int a[];
};

int main()
{
    struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int));
    if (ps == NULL)
    {
        printf("%s\n", strerror(errno));
        return(-1);
    }
    //使用
    ps->i = 100;
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        ps->a[i] = i;
    }
    //...

    //数组空间不够,希望调整为20个int
    struct st_type* ptr = (struct st_type*)realloc(ps, sizeof(struct st_type) + 20 * sizeof(int));
    if (ptr == NULL)
    {
        printf("扩展空间失败\n");
        return -1;
    }
    else
    {
        ps = ptr;
    }
    //释放
    free(ps);
    ps = NULL;
    return 0;
}

5.3 柔型数组的优势

那有同学就想把st_type结构体设计成这个样子,也可以实现:

struct st_type
{
    int i;//4byte
    int* a;//4byte
};

在这里插入图片描述

于是上面代码经过变换,仍有相同功能:

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

struct st_type
{
    int i;//4byte
    int* a;//4byte
};

int main()
{
    struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type));
    ps->i = 100;

    ps->a= (int*)malloc(10 * sizeof(int));
    //使用
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        ps->a[i] = i;
    }
    for (i = 0; i < 10; i++)
    {
        printf("%d ", ps->a[i]);
    }
    //...

    //若a指向的空间不够,希望调整到20个int
    int* ptr = (int*)realloc(ps->a, 20 * sizeof(int));
    if (ptr == NULL)
    {
        printf("扩容失败\n");
        return -1;
    }
    else
    {
        ps->a = ptr;
    }
    //使用
    //...

    //两次释放---注意先后顺序
    free(ps->a);
    ps->a = NULL;
    free(ps);
    ps = NULL;
    return 0;
}

中间小插曲的运行结果:
在这里插入图片描述

:innocent:对比两段代码,虽然都实现了同样的功能,但也可见柔性数组的优势:

:snowman:1. 方便内存释放
只要释放一次;且 malloc次数少,那么 出现动态内存分配相关错误的可能性会减少
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要 free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次 free就可以把所有的内存也给释放掉。
:snowman:2. 有利于访问速度
malloc次数多,产生的 内存碎片比较多,内存空间利用率比较低。
连续的内存有益于提高访问速度。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)
在这里插入图片描述

柔性数组面试考过不多,这也是单拎出来的原因,不过还是希望小伙伴都能了解一下!
动态内存开辟相关内容至此结束

相关文章
|
6月前
|
程序员 C语言 C++
动态内存管理与柔性数组2
动态内存管理与柔性数组
25 0
|
6月前
|
编译器
动态内存管理与柔性数组 1
动态内存管理与柔性数组
23 0
|
6月前
|
程序员 编译器 C语言
动态内存函数,内存开辟,柔性数组(超详细)
动态内存函数,内存开辟,柔性数组(超详细)
38 0
|
5月前
|
C语言 Python
动态内存管理(下)
动态内存管理(下)
29 0
|
8月前
|
编译器 C语言 C++
动态内存分配(3)——柔性数组
动态内存分配(3)——柔性数组
|
4月前
|
程序员 编译器 C语言
C语言动态内存管理以及柔性数组
C语言动态内存管理以及柔性数组
50 0
|
5月前
C进阶-动态内存管理+柔性数组(1)
C进阶-动态内存管理+柔性数组
25 0
|
5月前
|
编译器 C语言 C++
C进阶-动态内存管理+柔性数组(2)
C进阶-动态内存管理+柔性数组
34 0
|
5月前
|
小程序 C语言 C++
C语言之动态内存管理_柔性数组篇(2)
C语言之动态内存管理_柔性数组篇(2)
33 0
|
5月前
|
C语言 C++
C++中的动态内存管理
C++中的动态内存管理