結構體的嵌套,結構體內定義結構體。


注:

轉自https://www.cnblogs.com/renyuan/archive/2012/11/30/2796792.html

結構體的嵌套問題

 

結構體的自引用(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在定義之前 就被使用。

  這里補充一點,如果是在tag_b 里直接用A定義*ap是可以的,而且這里也可直接用ap而不是指針的形式。這是因為tag_a在tag_b之前定義的,所以可以。但是上面的tag_a里面聲明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 ;

看到上面這段,瞬間秒懂,謝博主~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM