优秀的编程知识分享平台

网站首页 > 技术文章 正文

C编程技巧——柔性数组(c 柔性数组)

nanyue 2024-08-25 10:36:49 技术文章 5 ℃

定义:结构体中最后一个元素允许是未知大小的数组,这个数组就是柔性数组(soft array),也叫伸缩性数组。但结构中的柔性数组前面必须至少一个其他成员

例:

typedef struct
{
    uint8_t afn;              //功能码
    uint8_t seq;             //seq
    uint8_t payload[ ];   //payload
}package_info_t;

当然有的编译器会对这种定义报错,需改成如下定义:

typedef struct
{
    uint8_t afn;               //功能码
    uint8_t seq;               //seq
    uint8_t payload[0];   //payload
}package_info_t;

这边使用柔性数组,是用来解析不定长通信包的。一般在解析不定长数据包时,最懒的方法是把载荷(payload)的最大长度设置为数组缓存的大小,比如最大的通信包载荷是1000,那么可以定义如下

#define MAX_LEN 1000
typedef struct
{
    uint8_t afn;                             //功能码
    uint8_t seq;                             //seq
    uint8_t payload[MAX_LEN];   //payload
}package_info_t;

这种固定长度的定义,显然处理起来简单,但是在载荷变化时,比如数据包的载荷有时候为5、12、50等等远小于MAX_LEN长度时,是及其浪费内存资源的。这时候可以考虑采用动态内存开辟的方式来实现资源的集约化,柔性数组的使用就满足了该场景。

例:

struct flexible_array
{
    int state;
    int value[0];     //柔性数组成员,也可以写value[];
};

int main()
{
    //柔性数组申请10个int的空间
    struct flexible_array *p=(struct flexible_array*)malloc(sizeof(struct flexible_array) + 10 * sizeof(int));
    if (p == NULL)
    {
        return -1;
    }

    int j = 0;
    for (j = 0;j < 10;j++)
    {
        p->value[j] = j;
    }
    for (j = 0;j < 10;j++)
    {
        printf("%d ", p->value[j]);
    }
    printf("\n");

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

这个例子是柔性数组动态申请10个int的内存空间来使用,结果如下

这里需要注意:

对于编译器而言,此时长度为0的数组并不占用空间,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量!!!

struct flexible_array *p=(struct flexible_array*)malloc(sizeof(struct flexible_array) + 10 * sizeof(int));

当然柔性数组还可以扩展伸缩,只需用realloc:

struct flexible_array* ptr=realloc(p, sizeof(struct flexible_array) + 15 * sizeof(int));

这就是柔性数组的用法。

当然在解析不定长数据包时,除了使用柔性数组,也可以采用指针的方式来实现动态内存分配:

struct memory
{
    int      state;
    char * p_value;     //指针;
};

实现如下:

   //首先是结构体分配内存,获取指针
    struct memory *p = (struct memory*)malloc(sizeof(struct memory));
    if(p == NULL)
    {
        return -1;
    }

    p->state = 0;
   //其次,获取一个10个char型的内存空间
    p->p_value = (char *)malloc(10 * sizeof(char));
    if(p->p_value == NULL)
    {
        return -1;
    }

在内存释放时的操作如下

     //释放,必须先释放p_value;否则p一释放,p_value就丢失了指向
    free(p->p_value);
    p->p_value = NULL;
    free(p);
    p = NULL;

乍一看,和上面的柔性数组使用区别不大?

这种方式,动态申请了两块内存,那么这两块内存是不连续的,这样就导致了内存碎片化。柔性数组内存是连续的,是一块内存,连续的内存有益于提高访问速度。

其次,在释放内存时,需要分两次释放,而且是依次释放,这在独立编程时是问题不大,但是如果把这部分封装成API,那么如果封装接口不完善,没有做到把申请的内存都释放的话(比如没有结构体内部指针内存的释放),就容易有内存泄漏的风险。

Tags:

最近发表
标签列表