• (转载)C语言的零长数组


    在标准 C 或者 C++ 中由于不支持 0 长度的数组,所以 int array[0]; 这样的定义是非法的。不过有些编译器的扩展功能支持 0 长度的数组。

    在 C 中,0 长度的数组的主要用途是用来作为结构体的最后一个成员,然后用它来访问此结构体对象之后的一段内存(通常是动态分配的内存)。由于其非标准性,在程序中尽量避免使用 0 长度的数组。作为替换,可以使用 C99 标准中的不完整数组来替换 0 长度的数组定义。如:

    CODE:
    struct X {
      /* Members */
      int array[];  /* Do not write int array[0]; since it is not standard. */
    };

    >> 但是我的如下代码是能顺利编译且不出警告和错误,而且能运行的啊
    >> int array[0]
    >> *array = 1;

    程序中可能出现的错误有多种。一是语法错误,这类错误很容易在编译阶段检查出来。除此之外,还有一类错误在编译阶段不能或者很难检查出来,这类错误被称为“无定义”,其结果是不确定的。

    上面的代码中因为有越界访问数组这一错误存在,所以它的行为(执行的结果)是无定义的。
    应用比如:
    CODE:
    struct A {
      int a, b;
      char data[0];
      /* do not write fields below */
    };

    struct A *p;

    int n = 100, i;
    p = malloc(sizeof(struct A) + n);
    for (i = 0; i < n; ++i)
    p->data[i] = 1;

    摘自:http://hi.baidu.com/juneshine/blog/item/5aed91458bf5063e86947309.html

    在GNU的指南中,它是如此写道:

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

    //...ommit code here

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

    这个用法主要用于变长Buffer,struct line的大小为4,结构体中的contents[0]不占用任何空间,甚至是一个指针的空间都不占,contents在这儿只是表示一个常量指针,这个特性是用编译器来实现的,即在使用thisline->contents的时候,这个指针就是表示分配内存地址中的某块buffer,比如malloc (sizeof (struct line) + this_length)返回的是0x8f00a40,thisline->contents指向的位置就是(0x8f00a40 + sizeof(struct line)),而这儿sizeof(struct line)仅仅是一个int的四字节。

    对于这个用法,我们定义的结构体指针可以指向任意长度的内存buffer,这个技巧在变长buffer中使用起来相当方便。可能有朋友说,为什么不把最后的contents直接定义为一个指针呢?这儿的差别是这样的,如果定义为一个指针,它需要占用4Bytes,并且在申请好内存后必须人为赋地址才可以。如果使用这个用法,这个常量指针不占用空间,并且无需赋值。

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

    ——>如果将零长数组array换成指针*array来使用的话,指针必须重新分配一段内存之后才能使用,那么当想要用socket发送结构体指针的时候,并不会将指针array申请的内存发送过去,因为是不连续的,所有接受socket发送来的数据后,会发现该数据并不是自己想要的。
     
     
     

    例子1:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct Student
    {
        int age;
        float tall;
        int addr_len;
        char addr[];
    };
    
    int main(int argc, char** argv)
    {
        int len = 100;
        struct Student* ptr;
        ptr = malloc(sizeof(struct Student) + sizeof(char) * len);
    
        ptr->age = 24;
        ptr->tall = 176.5;
        ptr->addr_len = len;
        strncpy(ptr->addr, "ZhuHai", sizeof("ZhuHai"));
    
        free(ptr);  // 一次性释放malloc()分配的内存
    
        return 0;
    }

    例子2:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct Student
    {
        int age;
        float tall;
        char *addr;
    };
    
    int main(int argc, char** argv)
    {
        struct Student* ptr;
      // 不仅仅要分配两次内存 ptr
    = malloc(sizeof(struct Student)); ptr->addr = malloc(sizeof(char) * 100); ptr->age = 24; ptr->tall = 176.5; strncpy(ptr->addr, "ZhuHai", sizeof("ZhuHai"));
      // 而且要释放两次内存,并且它们的顺序不能颠倒了,否则会造成内存泄露 free(ptr
    ->addr); free(ptr); return 0; }

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

    struct Student
    {
        int age;
        float tall;
        int add_len;
        char addr[0];  // 并不占内存
    };

    int main(int argc, char** argv)
    {
        printf("The size: %d\n", sizeof(struct Student));

        return 0;
    }

    程序输出:

    12

    可以看到长度为0那个数组,在实现上确实不占内存的。

  • 相关阅读:
    KVM_虚拟化技术
    Java面试题全集
    Web负载均衡与分布式架构
    Tomcat的目录结构和配置文件详解
    Apache HTTP Server 与 Tomcat 的三种连接方式介绍
    Java文件上传
    基础知识《十一》Java异常处理总结
    《转载》renameTo文件在windows环境下可以,在linux中报错
    《转载》Linux服务之搭建FTP服务器&&分布式文件服务器的比较
    oracle闪回数据
  • 原文地址:https://www.cnblogs.com/Robotke1/p/3074065.html
Copyright © 2020-2023  润新知