在Linux源代码中,有很多的结构体最后都定义了一个元素个数为0个的数组,如/usr/include/linux/if_pppox.h中有这样一个结构体:
struct pppoe_tag {
__u16 tag_type;
__u16 tag_len;
char tag_data[0];
} __attribute ((packed));
又如在asterisk的源码中的Pbx.c:
struct ast_ignorepat {
const char *registrar;
struct ast_ignorepat *next;
char pattern[0];
};
结构体最后的长度为0的数组是GCC中广泛使用技巧,常用来构成可变长缓冲区。
在创建时,malloc一段结构体大小加上可变长数据长度的空间给它:malloc(sizeof(struct pppoe_tag)+ buff_len),可变长部分按数组访问方式访问;释放时,直接把整个结构体free掉就可以了。
例子如下:
struct pppoe_tag *sample_tag;
__u16 sample_tag_len = 10;
sample_tag = (struct pppoe_tag *)malloc( sizeof(struct pppoe_tag) + sizeof(char) * sample_tag_len);
sample_tag->tag_type = 0xffff;
sample_tag->tag_len = sample_tag_len;
sample_tag->tag_data[0]=….
…
释放时:
free(sample_tag)
这样的好处有两个:
一次分配解决问题,省了不少麻烦。为了防止内存泄漏,如果是分两次分配(结构体和缓冲区),那么要是第二次malloc失败了,必须回滚释放第一个分配的结构体。这样带来了编码麻烦。
其次,分配了第二个缓冲区以后,如果结构里面用的是指针,还要为这个指针赋值。同样,在free这个buffer的时候,用指针也要两次free。而且小内存的管理是非常困难的,如果用指针,这个buffer的struct部分就是小内存了,在系统内存在多了势必严重影响内存管理的性能。要是用空数组把struct和实际数据缓冲区一次分配大块问题,就没有这个问题。
所以,结构体最后使用0或1的长度数组的原因,主要是为了方便的管理内存缓冲区,如果你直接使用指针而不使用数组,那么,你在分配内存缓冲区时,就必须分配结构体一次,然后再分配结构体内的指针一次,(而此时分配的内存已经与结构体的内存不连续了,所以要分别管理即申请和释放)而如果使用数组,那么只需要一次就可以全部分配出来;反过来,释放时也是一样,使用数组,一次释放,使用指针,得先释放结构体内的指针,再释放结构体。还不能颠倒次序。
这个技巧其实就是分配一段连续的的内存,减少内存的碎片化。在Linux操作系统开发或者嵌入式开发,这种技巧尤其常见。
PS:某些编译器不支持长度为0的数组的定义,在这种情况下只要将它定义成char tag_data[1],使用方法相同。
相关推荐
// 创建一个包含10个元素的数组 numbers = new int[20]; // 现在数组包含20个元素 ``` #### 二、数组的声明与类型 C#支持三种主要类型的数组: 1. **一维数组**:是最基本的数组类型,如`int[] numbers;`。 2. *...
在这个定义中,`name` 是一个字符数组,长度为 15。现在,我们想给这个结构体赋值,例如,学号为 7,姓名为 "Zhangsan"。 要给结构体赋值,我们需要使用 `memset` 函数来初始化结构体,然后使用赋值语句来设置成员...
柔性数组成员允许结构体的最后一个元素是一个长度为0的数组,这样做可以灵活地根据需要分配结构体后面的内存空间。 最后,文档提到将会有第二季的内容提供,这表明了结构体系列的深入讲解将陆续推出,为读者提供更...
在这个例子中,`myStruct`类型有三个成员:一个整数,一个实数和一个长度为20的字符变量。通过定义结构体,我们可以更清晰地组织代码,提高可读性和复用性。例如,如果我们正在模拟粒子系统,可以定义一个结构体包含...
结构体是一种数据的归类方式,相比数组或变量更具有整体全面性,例如一个数组只可以放一些按照元素顺序存放的单元变量,即 buffer = {x, x, x, x, x…},i 有多大,数组内元素就有多少。那么我们这时候如果我们用这...
数组是C语言中基本的数据结构之一,它是一个有序数据的集合,其中的每个元素都具有相同的类型。数组的定义方式是使用类型说明符后跟数组名和方括号内的常量表达式,如`int a[10]`,这表示了一个包含10个整数的数组。...
// 定义了一个结构体数组,最多可以存储10条联系人信息 ``` - **用途**:用于组织和管理相关的数据字段。 #### 二、基本操作函数实现 1. **删除功能** (`del()`): - **功能描述**:根据用户输入的索引值,删除...
本文将探讨如何使用分治策略来解决一个特定的问题——在一个包含n个整数的数组中找到第二大的元素。 #### 分治算法原理 分治(Divide and Conquer)是一种重要的算法设计策略,它通过递归地将一个问题分解成两个或...
3. 索引:数组的索引从0开始,`arr[0]` 是数组的第一个元素,`arr[4]` 是最后一个元素(在上面的例子中)。 4. 遍历:可以通过for循环遍历数组,例如 `for(int i = 0; i ; i++) { cout [i]; }`。 二、指针 1. ...
`sizeof`一个字符串常量会返回字符数组的长度,不包括结束的`\0`。例如: ```c++ char str[] = "Hello"; printf("Size of string: %zu\n", sizeof(str)); // 输出6(不包括'\0') ``` 但是,对于动态分配的字符串...
3. 初始化数组,为每个候选人分配一个`Candidate`结构体实例,并设置初始票数。 4. 设计投票功能,通过输入候选人的编号,增加对应候选人的票数。 5. 实现计票功能,遍历`votes`数组,计算每个候选人的总票数。 6. ...
在结构体数组中,每个元素都是一个完整的结构体实例,可以存储相应的成员数据。例如,上述的`stu`数组中,`stu[0]`到`stu[4]`分别代表了五个不同的学生,每个学生都有自己的编号、姓名、身份证号、生日、性别、年龄...
在C++编程中,结构体的长度计算是一个非常重要的问题。很多开发者都知道,结构体的sizeof值,不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。这是一个非常基础的问题,但是却经常被忽视...
定义了一个整形数组,数组名为a,此数组有6个元素。 在定义数组时,需要指定数组中元素的个数,方括弧中的常量表达式用来表示元素的个数,即数组长度。例如,int a[6];定义了一个整形数组,数组名为a,此数组有6个...
在这个例子中,`students` 是一个结构体数组,每个元素代表一个学生的信息。 在实际应用中,熟练掌握单元数组和结构体的操作能让你更好地应对各种复杂问题。例如,你可以使用结构体来表示物理系统中的组件,每个...
在C++编程中,"不定长数组"是一个关键概念,特别是在处理动态数据时。传统的C++数组在声明时需要指定其长度,而不定长数组允许我们在运行时根据需要分配和调整大小。这种特性使得程序更加灵活,能更好地适应变化的...
接下来,我们需要一个排序函数,它接受一个指向结构体数组的指针、数组长度以及一个排序依据的字段名。我们可以使用`strcmp()`函数来比较字符串字段,对于整型字段可以直接使用比较运算符。这里以冒泡排序为例,但你...
最后,将数组的最后一个元素(即原位置9之后的元素)设置为0,表示已删除。 ### 实现步骤 1. **初始化**:设置i和j为0,开始遍历数组。 2. **查找元素**:当i遍历到的元素等于目标值时,停止移动i。 3. **元素迁移...
对于结构体数组 `S`,`fieldnames(S)` 返回一个包含所有字段名的 cell 数组,`length(fieldnames(S))` 就是结构体数组中字段的数量。而对于 cell 数组 `C`,`length(C)` 直接返回 cell 数组的元素个数,与 `numel(C)...
当我们有一个一维数组,如 `a = [1, 2, 3, 4]`,我们可以直接调用 `length(a)` 来得到数组的长度,即它的元素个数。在这个例子中,`len_a = length(a)` 后,`len_a` 的值为 4。然而,当数组是多维的,例如 `b = [1 2...