0长度数组的使用

0长度的数组在ISO C和C++的规格说明书中是不允许的,但是GCC的C99支持的这种用法。
GCC对0长度数组的文档参考:“Arrays of Length Zero

如下代码片段,哪个更简洁更灵活,看一眼就知道了:

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

typedef struct tagArray
{
   int length;
   char contents[]; //这个成员必须是结构体的最后一个成员。
}ARRAY_S;

typedef struct tagPointer
{
    int length;
    char *contents;
}POINTER_S;

int main()
{
    int array_length = 10;
    ARRAY_S *pArray  = (ARRAY_S*)malloc (sizeof(ARRAY_S) + array_length);
    POINTER_S *pPointer = NULL;

    if (NULL == pArray)
    {
        return 0;
    }

    pArray->length = array_length;
    memset(pArray->contents, ‘a‘, array_length);

    free(pArray);

    pPointer = (POINTER_S*)malloc(sizeof(POINTER_S));
    if(pPointer == NULL)
    {
        return 0;
    }
    memset(pPointer, 0, sizeof(POINTER_S));
    pPointer->length = array_length;
    pPointer->contents = (char*)malloc(array_length);
    if (pPointer->contents == NULL)
    {
        free(pPointer);
        return 0;
    }
    memset(pPointer->contents, ‘a‘, array_length);

    free(pPointer->contents);
    free(pPointer);

    return 0;
}
第一种结构体的定义:想给一个结构体内的数据分配一个连续的内存,有两个好处:

(1)方便内存释放。
如果我们的代码提供给别人使用,你在里面做了二次内存分配,并把整个结构体返回给用户。
用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。
所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

(2)有利于访问速度。
连续的内存有益于提高访问速度,也有益于减少内存碎片。

第二种结构体的使用:需要分配两次内存以及释放两次内存,在检查申请内存成功与否的代码量上看也明显没有第一种更简洁。

看看内存是怎么个连续的,用gdb的x命令来查看:(ARRAY_S中的那个char contents[]不占用结构体的内存,
所以ARRAY_S就只有一个int成员,4个字节,而我们还要为contents[]分配10个字节长度,所以,一共是14个字节):

 1 (gdb) p pArray
 2 $1 = (ARRAY_S *) 0x804b008
 3 (gdb) p *pArray
 4 $2 = {length = 10, contents = 0x804b00c "aaaaaaaaaa"}
 5 (gdb) p pArray ->contents
 6 $3 = 0x804b00c "aaaaaaaaaa"
 7 (gdb) x/14b pArray
 8 0x804b008:      10      0       0       0       97      97      97      97
 9 0x804b010:      97      97      97      97      97      97  从上面的内存布局我们可以看到,前4个字节是 int length,后10个字节就是char contents[]。

  如果用指针的话,会变成这个样子:
10 (gdb) p pPointer
11 $4 = (POINTER_S *) 0x804b020
12 (gdb) p *pPointer
13 $5 = {length = 10, contents = 0x804b030 "aaaaaaaaaa"}
14 (gdb) p pPointer ->contents
15 $6 = 0x804b030 "aaaaaaaaaa"
16 (gdb) x/16b pPointer
17 0x804b020:      10      0       0       0       48      -80     4       8
18 0x804b028:      0       0       0       0       17      0       0       0
19 (gdb) x/10b pPointer ->contents
20 0x804b030:      97      97      97      97      97      97      97      97
21 0x804b038:      97      97
22 (gdb) x/16x pPointer
23 0x804b020:      0x0a    0x00    0x00    0x00    0x30    0xb0    0x04    0x08
24 0x804b028:      0x00    0x00    0x00    0x00    0x11    0x00    0x00    0x00

第17行前四个字节是 int length,后四个字节是contents的地址。
    第23行以16进制显示,地址是: 0x30 0xb0 0x04 0x08, 即:0x0804b030。
    第20行和第21行是char* contents指向的内容。

因此,可以看出其中的差别:数组的原地就是内容,而指针的那里保存的是内容的地址。


0长度数组的使用,布布扣,bubuko.com

时间: 2024-10-23 08:29:05

0长度数组的使用的相关文章

【代码优化】返回0长度数组或者集合

改掉你从C语言继承过来的习惯,我们在java中没理由返回类型为数组或者集合返回null. private final List<Cheese> InStock =...; public Cheese[] getCheeses() { if( InStock.size() ==0){ return null; } } 这种是我们经常使用的 返回的模式,这就带来在应用Cheese数组的时候 都需要判断数组是否为null. Cheese[] cheeses= shop.getCheeses(); i

C语言0长度数组(柔性数组)

0长度数组,又称为柔性数组(flexible array),通常用来实现变长数组,常见于TLV(type-length-value)的数据结构中.在标准 C 和 C++ 中,不允许用 0 长度数组,但在 GNU C 中,却可以定义 0 长度数组.通常会拿手册中给的例子来说明 struct line { int length; char contents[0]; } 从打印出来的结构体尺寸 sizeof (struct line) = 4 (和编译器有关,看内存对齐规则),可以看到contents

结构体中最后一个成员为[0]或[1]长度数组(柔性数组成员)的用法

结构体中最后一个成员为[0]长度数组的用法:这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势:(1).不需要初始化,数组名直接就是所在的偏移:(2).不占任何空间,指针需要占用int长度空间,空数组不占任何空间.“这个数组不占用任何内存”,意味着这样的结构节省空间:“该数组的内存地址就和它后面的元素地址相同”,意味着无需初始化,数组名就是后面元素的地址,直接就能当指针使用. 这样的写法最适合制作动态buffer,因为可以这样分配空间malloc(sizeof(struc

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

前面在看Xen的源码时,遇到了一段代码,如下所示: 注意上面最后一行的代码,这里定义了一个长度为的数组,这种用法可以吗?为什么可以使用长度为0 的数组?长度为的数组到底怎么使用?……这篇文章主要针对该问题进行简单的讲解.废话不多说了,现在就开始. 长度为的数组在标准c和c++中是不允许的,如果使用长度为的数组,编译时会产生错误,提示数组长度不能为.但在GNUc中,这种用法却是合法的.它的最典型的用法就是位于数组中的最后一项,如上面所示,这样做主要是为了方便内存缓冲区的管理.如果你将上面的长度为的

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

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

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++扩展,如果你的编译器支持这个扩展,你就

读陈浩的《C语言结构体里的成员数组和指针》总结,零长度数组

原文链接:C语言结构体里的成员数组和指针 复制如下: 单看这文章的标题,你可能会觉得好像没什么意思.你先别下这个结论,相信这篇文章会对你理解C语言有帮助.这篇文章产生的背景是在微博上,看到@Laruence同学出了一个关于C语言的题,微博链接.微博截图如下.我觉得好多人对这段代码的理解还不够深入,所以写下了这篇文章. 为了方便你把代码copy过去编译和调试,我把代码列在下面: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h>

蓝牙通信中读取固定长度数组的解决

2014-05-05 18:10 今天主要忙于工作.之前遇到一个问题,今天得以解决. 问题的描叙:需要从输入流中读取固定长度的字节数组. 问题的解决:今天参考了网上的资料.解决了. 注释部分:之前是通过拷贝数组进行解决,但是难以解决. 解决的代码如下: public synchronized void run() { byte[] buffer = new byte[16]; int bytes = 0; while (mmInStream != null) { try { // 通过连接的端口

c/c++的0长数组(柔性数组)

在标准C和C++中0长数组如charArray[0]是不允许使用的,因为这从语义逻辑上看,是完全没有意义的. 但是,GUN中却允许使用,而且,很多时候,应用在了变长结构体中,如: StructPacket { Int state; Int len; Char cData[0]; //这里的0长结构体就为变长结构体提供了非常好的支持,可以指向独立的数据空间 }; 首先对0长数组做一个解释: 用途 :长度为0的数组的主要用途是为了满足需要变长度的结构体. 用法 :在一个结构体的最后 ,申明一个长度为