標籤:c 指標 結構體 struct
第十章 結構和聯合
這個部分先介紹了.運算子,可以供直接存取,還介紹了->運算子,它代替結構體指標的間接訪問操作(*struct).xxx
這一章新手理解起來不算太難,沒有學過作業系統的話理解位段、對齊等概念會有一些問題。
越發的說明了指標和記憶體絕對是C的核心。
總結:
結構聲明列出了結構包含的成員列表,不同類型的值可以儲存在一起。
不同的結構聲明即使他們的成員列表相同也被認為是不同的類型。
聲明結構時使用typedef建立一種新類型是一個好方法。
typedef struct
{
int a;
char b;
float c;
}simple;
跟結構標籤的結果幾乎相同。區別在於simple現在是一個類型名而不是結構體,以後聲明就是下面這個樣子。
simple x;
simple y[20], *z;
結構不能包含類型也是這個結構的成員,否則在分配地址的時候,會出現無窮大。但是可以包含一個指向這個結構的指標。
這個常常用在鏈式結構中。為了聲明兩個結構,每個結構都包含一個指向對方的指標的成員。
初始化的時候可以由一個花括弧包圍的值列表進行初始化。
編譯器為一個結構變數的成員分配記憶體時要滿足它們的邊界對齊要求。在實現結構儲存的邊界對齊時,可能會浪費部分空間。根據邊界對齊要求降序排列結構成員可以最大限度地減少結構儲存中浪費的記憶體空間。
如果想要減少對齊造成的損失,一般來說聲明的過程中要降序排列。可以利用offstof宏(stddef.h)+sizeof來找個更好的辦法。
結構可以作為形參傳遞給函數,也可以作為返回值返回但是絕對不提倡!!!嚴重浪費記憶體空間。
最好形參和返回值都用指標,如果怕修改結構本身,那麼就加個const!
位段個人不是理解很深,理解來看是可以將長度為奇數的值封裝在一起節省空間的。
Union和struct是兩個不同的故事。所有Union的成員都儲存於同一個記憶體位置。也可以進行初始化,但是初始化必需與聯合第一個成員類型匹配。
關於初始化:
union{
int a;
float b;
char c[4];
} x = {5};
這樣就把x.a初始為5。
警告:
1、具有相同成員列表的結構聲明產生不同類型。
這就像函數一樣,跟聲明關係很大。
2、使用typedef為一個自引用的結構定義名字時應該小心。
自引用一定要記住,要引用指標。
3、向函數傳遞結構參數是低效的。
要對記憶體的形參進行拷貝,這份拷貝放在記憶體裡實在是太浪費空間。
編程提示:
1、typedef聲明放在標頭檔中。到是用到就#include回來。
2、結構成員的最佳排列形式並不一定就是考慮邊界對齊而浪費記憶體空間最少的那種相片順序。
很顯然,為了對齊,有時候你不得不打亂聲明的順序,從而導致可讀性的降低。
3、把位段成員顯式得聲明為signed int 或者 unsigned int類型。
4、位段是不可抑制的。
5、位段使原始碼中位的運算式更加清楚。
問題:
1、成員和數組元素有什麼區別?
成員可以具備不同的類型,數組不行。
2、結構名和數組名有什麼不同?
數組名是一個指標常量。但是結構名就是個標籤tag,跟class名類似,沒有執行個體的話,是不會對其分配記憶體的。
3、結構的聲明:
struct tag{member-list } variable-list;
tag、member-list、variable-list三者必需有二。
C和指標 (pointers on C)——第十章:結構體和聯合(上)