(转)C语言中长度为0的数组

前面在看Xen的源码时,遇到了一段代码,如下所示:

注意上面最后一行的代码,这里定义了一个长度为的数组,这种用法可以吗?为什么可以使用长度为0 的数组?长度为的数组到底怎么使用?……这篇文章主要针对该问题进行简单的讲解。废话不多说了,现在就开始。

长度为的数组在标准c和c++中是不允许的,如果使用长度为的数组,编译时会产生错误,提示数组长度不能为。但在GNUc中,这种用法却是合法的。它的最典型的用法就是位于数组中的最后一项,如上面所示,这样做主要是为了方便内存缓冲区的管理。如果你将上面的长度为的数组换为指针,那么在分配内存时,需采用两步:首先,需为结构体分配一块内存空间;其次再为结构体中的成员变量分配内存空间。这样两次分配的内存是不连续的,需要分别对其进行管理。当使用长度为的数组时,则是采用一次分配的原则,一次性将所需的内存全部分配给它。相反,释放时也是一样的。

对于长度为的数组,在gcc手册中,有如下一段代码片段:

struct line {
    int length;
    char contents[0];
};

struct line *thisline = (struct line *) malloc(sizeof(struct line) + this_length);

thisline->length = this_length;

这段代码的主要含义是定义了一个结构体,并对其进行初始化,上面结构体的第二个成员变量contents[0]事实上是不占内存空间的,因此整个结构体的长度sizeof(struct line)为4。当采用malloc为其申请内存空间时,如上所示,申请了一段长度为结构体长度加可变长度的内存空间给结构体类型的指针,这时contents就指向申请的可变长度的内存空间。由于是一次申请的,所以这段可变长度的内存空间和前面的结构体长度的内存空间是连续的。对于这段可变长度的内存空间,可以采用数组的方式对其进行访问。对于整个结构体,当不再使用时,可以使用free函数一次性对其进行释放,而不必像指针那样分别释放。

下面举例进行说明:

#include <stdio.h>
#include <stdlib.h>
#define LENGTH 10

struct test1 {
    int a;
    int *b;
}__attribute((packed));

struct test2 {
    int a;
    int b[0];
}__attribute((packed));

struct test3 {
    int a;
    int b[1];
}__attribute((packed));

int main() {
    struct test1 *var1;
    struct test2 *var2;
    struct test3 *var3;
    int i;

    printf("the length of struct test1:%d\n", sizeof(struct test1));
    printf("the length of struct test2:%d\n", sizeof(struct test2));
    printf("the length of struct test3:%d\n", sizeof(struct test3));

    var1 = (struct test1*) malloc(sizeof(struct test1));
    var1->a = 1;
    var1->b = (int *) malloc(sizeof(int));
    *var1->b = 1;
    printf("\nvar1->a=%d,*(var1->b)=%d\n", var1->a, *var1->b);

    var2 = (struct test2*) malloc(sizeof(struct test2) + sizeof(int) * LENGTH);
    var2->a = 2;
    printf("\nvar2->a=%d\n", var2->a);
    for (i = 0; i < LENGTH; i++) {
        var2->b[i] = i;
        printf("var2->b[i]=%d\t", var2->b[i]);
    }
    printf("\n\n");

    var3 = (struct test3*) malloc(sizeof(struct test3));
    var3->a = 3;
    (var3->b)[0] = 3;
    printf("var3->a=%d,(var3->b)[0]=%d\n", var3->a, (var3->b)[0]);

    free(var1->b);
    free(var1);
    free(var2);
    free(var3);

}

这段程序的运行结果如下图所示:

从上面的结果可以看出:

1、 长度为的数组并不占有内存空间,而指针方式需要占用内存空间。

2、对于长度为数组,在申请内存空间时,采用一次性分配的原则进行;对于包含指针的结构体,才申请空间时需分别进行,释放时也需分别释放。

3、 对于长度为的数组的访问可采用数组方式进行。

原文地址:http://blog.csdn.net/zhaqiwen/article/details/7904515

(转)C语言中长度为0的数组,布布扣,bubuko.com

时间: 2024-08-23 22:59:26

(转)C语言中长度为0的数组的相关文章

C/C++ 中长度为0的数组

转载自http://www.cnblogs.com/tangxin-blog/p/5560699.html 参考文献:http://blog.csdn.net/zhaqiwen/article/details/7904515 近日在看项目中的框架代码时,发现了了一个奇特的语法:长度为0的数组例如 uint8_t buf[0]; 我从未见过这样的写法,所以在网上查了查资料,了解并记录下来. 在标准的C/C++中,长度为0的数组是不被允许的,它算是一个C/C++扩展,如果你的编译器支持这个扩展,你就

struct中长度为0的数组用途与原理

前言 在标准C和C++中,长度为0的数组是被禁止使用的.不过在GNUC中,存在一个非常奇怪的用法,那就是长度为0的数组,比如Array[0]; 很多人可能觉得不可思议,长度为0的数组是没有什么意义的,不过在这儿,它表示的完全是另外的一层意思, 这个特性是不可移植的, 所以,如果你致力于编写可移植,或者是稍稍需要跨平台的代码,这些Trick最好还是收起来的好. 本系列文章均系笔者所写,难免有一些错误或者纰漏,如果小伙伴们有好的建议或者更好的算法,请不吝赐教. 正文 在GNU的指南中,它是如此写道:

以杨辉三角为例,从内存角度简单分析C语言中的动态二维数组

学C语言,一定绕不过指针这一大难关,而指针最让人头疼的就是各种指向关系,一阶的指针还比较容易掌握,但一旦阶数一高,就很容易理不清楚其中的指向关系,现在我将通过杨辉三角为例,我会用四种方法从内存的角度简单分析动态二维数组,若有不足或错误之处,还请指出! 在讲这之前,以一维数组为例,先重新认识一下数组: int array[5] = {1, 2, 3, 4, 5}; 首先数组名称是该数组的首地址常量,即数组名称就是指针,就有&array[0] == array! 那么我们可以推出*array ==

C语言中的 (void*)0 与 (void)0

前几天看到一个宏, 它大概是这样的: #define assert_param(expr) ((expr) ? (void)0 : assert_failed((u8 *)__FILE__, __LINE__)) 代码的含意简单, 关键是那个 (void)0 的用法, 我还是第一次见到 我用 void 的时候, 有两种情况: 1.放到函数前面, 强调函数没有返回值, 也就是说函数不能作右值 如: void fun(int x); 2.放到函数形参里面, 强调函数无任何参数 如: int fun(

c语言中指针和多维数组的理解

1.复习指针和数组之间的特殊关系:不带方括号的数组名是一个指针,指向该数组的第一个元素. 2.多维数组: int multi[2][4];//声明一个二维数组作为举例 a.理解方式1:可以将数组看成行和列构成,即理解成2行4列.(传统的理解方法) 理解方式2:可以将multi数组看作一个包含2个元素,而其中每个元素都是一个包含4个int变量的数组. 3.图形理解方式 a.声明了一个multi的数组 b.数组multi包含两个元素(数组) c.其中每个元素(数组)包含4个元素(int变量) 4.回

D语言中字符串的操作

字符串的操作在软件开发中是特别重要的一个事情,因为基本上的编程都会使用到字符串,字符串操作的好坏决定着一个语言的好与差.在我做过的一个项目中曾经就出现过字符串操作性能问题. D语言字符串有 string,wstring,dstring三种类型,在D语言中字符串是使用字符数组定义的,三种类型分别对应char,wchar,dchar.char只有一个字节,wchar为双字节,dchar为三字节.对字符串的操作也相当于是对数组的操作,这跟其它语言不一样,C++中字符串是以string类来进行封装,它的

C语言中值得深入知识点----数组做函数参数、数组名a与&amp;a区别、数组名a的&quot;数据类型&quot;

1.数组作为函数参数 C语言中,数组做为函数的参数,退化为指针.数组作为参数传给函数时,传的是指针而不是数组,传递的是数组的首元素的地址.这里我们以将以整形变量排序来讲解. void sortArray(int a[] ,int num )以及void sortArray(int a[100] ,int num )都可以用void sortArray(int *a ,int num )表示.一般来说函数参数如果为数组,可以有两个参数,一个是数组名,一个是数组长度.对于排序而已,一般是要知道给定数

javascript语言中的毒瘤(下)

javascript语言中的毒瘤(下) 伪数组 Js中没有正真意义上的数组:这使得数组的使用非常容易,你不必给他们设置维度:而且永远不会产生越界错误:但它的性能相比正真的数组就糟糕了: Typeof 运算符不能辨别数组和对象,要判断一个值是否为数组,你还需要检查它的construtor属性:(也可以使用instanceof) function isArr(my_value) { if(my_value&& typeof my_value === 'object' && my

C语言中的位段(位域)

位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间.含有位段的结构体(联合体)称为位段结构.采用位段结构既能够节省空间,又方便于操作. 位段的定义格式为: type  [var]: digits 其中type只能为int,unsigned int,signed int三种类型(int型能不能表示负数视编译器而定,比如VC中int就默认是signed int,能够表示负数).位段名称var是可选参数,即可以省略.digits表示该位段所占的二进制位数. 一.位段的