轉載網址:http://tscsh.blog.163.com/blog/static/20032010320138249183520/
今天關於結構體一些疑問,在這里標記一下
1.定義與聲明
結構體的定義如下所示,struct為結構體關鍵字,tag為結構體的標志,member-list為結構體成員列表,其必須列出其所有成員;variable-list為此結構體聲明的變量。
1 struct tag 2 { 3 member-list 4 } variable-list ;
在一般情況下,tag、member-list、variable-list這3部分至少要出現2個。以下為示例:
1 //此聲明聲明了擁有3個成員的結構體,分別為整型的a,字符型的b和雙精度的c 2 //同時又聲明了結構體變量s1 3 //這個結構體並沒有標明其標簽 4 struct { 5 int a; 6 char b; 7 double c; 8 } s1; 9 10 11 //此聲明聲明了擁有3個成員的結構體,分別為整型的a,字符型的b和雙精度的c 12 //結構體的標簽被命名為SIMPLE,沒有聲明變量 13 struct SIMPLE{ 14 int a; 15 char b; 16 double c; 17 }; 18 //用SIMPLE標簽的結構體,另外聲明了變量t1、t2、t3 19 struct SIMPLE t1, t2[20], *t3; 20 //也可以用typedef創建新類型 21 typedef struct{ 22 int a; 23 char b; 24 double c; 25 } Simple2; 26 //現在可以用Simple2作為類型聲明新的結構體變量 27 Simple2 u1, u2[20], *u3;
在上面的聲明中,第一個和第二聲明被編譯器當作兩個完全不同的類型,即使他們的成員列表是一樣的,如果令t3=&s1,則是非法的。結構體的成員可以包含其他結構體,也可以包含指向自己結構體類型的指針,而通常這種指針的應用是為了實現一些更高級的數據結構如鏈表和樹等。
如果兩個結構體互相包含,則需要對其中一個結構體進行不完整聲明,如下所示:
//結構體A中包含指向結構體B的指針 struct A { struct B *partner; //other members; }; //結構體B中包含指向結構體A的指針,在A聲明完后,B也隨之進行聲明 struct B { struct A *partner; //other members; };
2. 自引用 結構體
1.1 不使用typedef時
錯誤的方式:
1 struct tag_1 2 { 3 struct tag_1 A; /* 結構體 */ 4 int value; 5 };
這種聲明是錯誤的,因為這種聲明實際上是一個無限循環,成員b是一個結構體,b的內部還會有成員是結構體,依次下去,無線循環。在分配內存的時候,由於無限嵌套,也無法確定這個結構體的長度,所以這種方式是非法的。
正確的方式: (使用指針):
1 struct tag_1 2 { 3 struct tag_1 *A; /* 指針 */ 4 int value; 5 };
由於指針的長度是確定的(在32位機器上指針長度為4),所以編譯器能夠確定該結構體的長度。
1.2 使用typedef 時
錯誤的方式:
1 typedef struct 2 { 3 int value; 4 NODE *link; /* 雖然也使用指針,但這里的問題是:NODE尚未被定義 */ 5 } NODE;
這里的目的是使用typedef為結構體創建一個別名NODEP。但是這里是錯誤的,因為類型名的作用域是從語句的結尾開始,而在結構體內部是不能使用的,因為還沒定義。
正確的方式:有三種,差別不大,使用哪種都可以。
1 /* 方法一 */ 2 typedef struct tag_1{ 3 int value; 4 struct tag_1 *link; 5 } NODE; 6 7 8 /* 方法二 */ 9 struct tag_2; 10 typedef struct tag_2 NODE; 11 struct tag_2{ 12 int value; 13 NODE *link; 14 }; 15 16 17 /* 方法三 */ 18 struct tag_3{ 19 int value; 20 struct tag_3 *link; 21 }; 22 typedef struct tag_3 NODE;
3. 相互引用 結構體
錯誤的方式:
1 typedef struct tag_a{ 2 int value; 3 B *bp; /* 類型B還沒有被定義 */ 4 } A; 5 6 typedef struct tag_b{ 7 int value; 8 A *ap; 9 } B;
錯誤的原因和上面一樣,這里類型B在定義之 前 就被使用。
正確的方式:(使用“不完全聲明”)
1 /* 方法一 */ 2 struct tag_a{ 3 struct tag_b *bp; /* 這里struct tag_b 還沒有定義,但編譯器可以接受 */ 4 int value; 5 }; 6 struct tag_b{ 7 struct tag_a *ap; 8 int value; 9 }; 10 typedef struct tag_a A; 11 typedef struct tag_b B; 12 13 14 /* 方法二 */ 15 struct tag_a; /* 使用結構體的不完整聲明(incomplete declaration) */ 16 struct tag_b; 17 typedef struct tag_a A; 18 typedef struct tag_b B; 19 struct tag_a{ 20 struct tag_b *bp; /* 這里struct tag_b 還沒有定義,但編譯器可以接受 */ 21 int value; 22 }; 23 struct tag_b{ 24 struct tag_a *ap; 25 int value; 26 };