zoukankan      html  css  js  c++  java
  • 结构体的嵌套问题

    结构体的自引用(self reference),就是在结构体内部,包含指向自身类型结构体的指针。

    结构体的相互引用(mutual reference),就是说在多个结构体中,都包含指向其他结构体的指针。

    1. 自引用结构体

    1.1 不使用typedef时

    错误的方式:

    struct tag_1{
        struct tag_1 A;  
        int value;
    };

            这种声明是错误的,因为这种声明实际上是一个无限循环,成员A是一个结构体,A的内部还会有成员是结构体,依次下去,无线循环。在分配内存的时候,由于无限嵌套,也无法确定这个结构体的长度,所以这种方式是非法的。

    正确的方式: (使用指针

    struct tag_1{
        struct tag_1 *A; 
        int value;
    };

            由于指针的长度是确定的(在32位机器上指针长度为4),所以编译器能够确定该结构体的长度。

    1.2 使用typedef 时

    错误的方式:

    typedef struct {
        int value;
        NODE *link; 
    } NODE;

      这里的目的是使用typedef为结构体创建一个别名NODEP。但是这里是错误的,因为类型名的作用域是从语句的结尾开始,而在结构体内部是不能使用的,因为还没定义。

    正确的方式:有三种,差别不大,使用哪种都可以。

    typedef struct tag_1{
        int value;
        struct tag_1 *link; 
    } NODE;
    
    
    struct tag_2;
    typedef struct tag_2 NODE;
    struct tag_2{
        int value;
        NODE *link;   
    };
    
    
    struct tag_3{
        int value;
        struct tag_3 *link; 
    };
    typedef struct tag_3 NODE;
    2. 相互引用 结构体

    错误的方式:

    typedef struct tag_a{
        int value;
        B *bp; 
    } A;
    
    typedef struct tag_b{
        int value;
        A *ap;
    } B;

           错误的原因和上面一样,这里类型B在定义之前 就被使用。

    正确的方式:(使用“不完全声明”)

    struct tag_a{
        struct tag_b *bp; 
        int value;
    };
    struct tag_b{
        struct tag_a *ap;
        int value;
    };
    typedef struct tag_a A;
    typedef struct tag_b B;
    
    
    
    struct tag_a;  
    struct tag_b;
    typedef struct tag_a A;
    typedef struct tag_b B;
    struct tag_a{
        struct tag_b *bp; 
        int value;
    };
    struct tag_b{
        struct tag_a *ap;
        int value;
    };

    嵌套结构体时应注意:

    结构体的自引用中,如下这种情况是非法的
    struct s_ref {
     int a;
     struct s_ref b;
     char c;
    };
    因为结构体内部又包含自身结构体类型b,这个长度不能确定,只能向下再查找,又包含自身结构体类型b,又再向下查找,如此循环,类似于永无出口的递归调用,是非法的。

    但很多时候,的确需要使用到自引用,有个技巧,如下:
    struct s_ref {
     int a;
     struct s_ref *b;  //注意这句与上面相同位置的区别
     char c;
    };
    这是合法的,因为此处是定义了一个指向结构体的指针,指针的大小在具体的机器平台和编译器环境中都是已知的(即使不同的平台环境的定义不完全相同)。所以不会导致上述的递归死循环。是合法和可行的。但是要提醒的是:这个指针看似指向自身,其实不是,而是指向同一类型的不同结构。
    链表和树的数据结构就都使用到此技巧。自身的结构体指针指向下一节点或者下一子树的地址。

    这里有一种情况值得注意:
    typedef struct {   //这里是结构体类型定义
     int a;
     s_ref *b;  //注意这句引用了结构体类型名
     char c;
    }s_ref ;
    这个结构体类型定义是为了定义类型名s_ref,但却失败了。因为结构体中就引用了结构类型名,而此时还没定义类型名。
    可以改为如下:
    typedef struct s_ref_t{   //这里是结构体类型定义和结构体标签
     int a;
     struct s_ref_t *b;  //注意这句与上面相同位置的区别,使用了标签
     char c;
    }s_ref ;
    这里将运行良好。

  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/renyuan/p/2796792.html
Copyright © 2011-2022 走看看