zoukankan      html  css  js  c++  java
  • 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指向的内容。

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

    
    
  • 相关阅读:
    Mybatis懒加载
    Mybatis 动态SQL
    Mybatis的多表查询
    linux selinux
    linux find/vi复制粘贴
    01-oracle限定查询-20190404
    awk
    sed
    windows删除指定日期前的文件
    win10 sshsecureshellclient删除profile保存的信息
  • 原文地址:https://www.cnblogs.com/eric-geoffrey/p/3822378.html
Copyright © 2011-2022 走看看