轉自:http://www.cnblogs.com/liangbo-1024/p/9188497.html
1.結構體的定義與聲明
結構體的定義如下所示,struct爲結構體關鍵字,tag爲結構體的標誌,member-list爲結構體成員列表,其必須列出其所有成員;variable-list爲此結構體聲明的變量。
struct tag
{
member-list
} variable-list ;
在一般情況下,tag、member-list、variable-list這3部分至少要出現2個。以下爲示例:
//此聲明聲明瞭擁有3個成員的結構體,分別爲整型的a,字符型的b和雙精度的c
//同時又聲明瞭結構體變量s1
//這個結構體並沒有標明其標籤
struct {
int a;
char b;
double c;
} s1;
//此聲明聲明瞭擁有3個成員的結構體,分別爲整型的a,字符型的b和雙精度的c
//結構體的標籤被命名爲SIMPLE,沒有聲明變量
struct SIMPLE{
int a;
char b;
double c;
};
//用SIMPLE標籤的結構體,另外聲明瞭變量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;
typedef struct SIMPLE0{
int a;
char b;
double c;
} Simple3; // Simple3爲SIMPLE0的別名
//也可以用typedef創建新類型(別名)
typedef struct{ //可以不要標籤
int a;
char b;
double c;
} Simple2;
//現在可以用Simple2作爲類型聲明新的結構體變量
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.自引用
2.1不使用typedef時
錯誤的方式:
struct tag_1
{
struct tag_1 A; /* 結構體 */
int value;
};
這種聲明是錯誤的,因爲這種聲明實際上是一個無限循環,成員b是一個結構體,b的內部還會有成員是結構體,依次下去,無線循環。在分配內存的時候,由於無限嵌套,也無法確定這個結構體的長度,所以這種方式是非法的。
正確的方式: (使用指針):
struct tag_1
{
struct tag_1 *A; /* 指針 */
int value;
};
由於指針的長度是確定的(在32位機器上指針長度爲4),所以編譯器能夠確定該結構體的長度。
1.2 使用typedef 時
錯誤的方式:
typedef struct
{
int value;
NODE *link; /* 雖然也使用指針,但這裏的問題是:NODE尚未被定義 */
} 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;
3. 相互引用 結構體
錯誤的方式:
typedef struct tag_a{
int value;
B *bp; /* 類型B還沒有被定義 */
} A;
typedef struct tag_b{
int value;
A *ap;
} B;
錯誤的原因和上面一樣,這裏類型B在定義之 前 就被使用。
正確的方式:(使用“不完全聲明”)
/* 方法一 */
struct tag_a{
struct tag_b *bp; /* 這裏struct tag_b 還沒有定義,但編譯器可以接受 */
int value;
};
struct tag_b{
struct tag_a *ap;
int value;
};
typedef struct tag_a A;
typedef struct tag_b B;
/* 方法二 */
struct tag_a; /* 使用結構體的不完整聲明(incomplete declaration) */
struct tag_b;
typedef struct tag_a A;
typedef struct tag_b B;
struct tag_a{
B *bp;
int value;
};
struct tag_b{
A *ap;
int value;
};