什麼是結構體?結構體是一些值的集合,這些值稱為成員變數。結構體的每個成員可以是不同型別的變數,可以是標量、陣列、指標,甚至是其他結構體。
結構體宣告
struct p
;//struct p名字
typedef struct
s; //重新命名 以後直接可以用s定義變數
struct
x;//可以編譯過,但不推薦,表示為建立了乙個叫x的結構體,這個後續不能再建立變數
結構體的自引用
typedef struct node
node;
//上面**便是乙個結構體的自引用(結構體內部包含乙個自己的指標)
//如果結構體內部的指標指向下個結構體,依次連線,便形成鍊錶
帶頭節點的單鏈表
結構體的訪問「.「訪問
指標訪問結構體內 用」->」
細心的可能會發現,上圖中,結構體a的位址和name的位址相同,age的位址比name的位址高,因此我們可以腦補出a結構體在記憶體中各個變數的大概位置。我相信這時一定有人要問:
name是9個位元組,可&age - &name = 12(0x88 - 0x7c = 12),多餘的兩個位元組是幹什麼的?
這兒,我們就要引入乙個很重要的…結構體內存對齊
結構體內存對齊:記憶體儲存:大小端結構體內存對齊規則:其他成員變數要對齊到某個數字(對齊數)的整數倍的位址處。 對齊數 = 編譯器預設的乙個對齊數 與 該成員大小的較小值。 vs中預設的值為4 ,linux中的預設值為4。第乙個成員在與結構體變數偏移量為0的位址處。
結構體總大小為最大對齊數的整數倍。
如果巢狀了結構體的情況,巢狀的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含巢狀結構體的對齊數)的整數倍。
為什麼要記憶體對齊?效能原因:資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。 原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。
//下面**中,s1和s2中的成員變數型別數量相等,但大小是否相等?
struct s1
a; struct s2
b; printf("s1 = %d\n", sizeof(a));
printf("s2 = %d\n", sizeof(b));
總結:結構體定義成員變數時,盡可能的讓小的集中且在前「#pragma pack(4) 」 可修改記憶體對齊數
位段的宣告和結構是類似的,有兩個不同:1.位段的成員必須是 int、unsigned int 或signed int 。
2.位段的成員名後邊有乙個冒號和乙個數字。
struct a
a; printf("%d\n", sizeof(a));
答案: 4位段的成員可以是 int unsigned int signed int 或者是 char (屬於整形家族)型別。位段的記憶體分配vs下:
位段的空間上是按照需要以4個位元組( int )或者1個位元組( char )的方式來開闢的。
位段涉及很多不確定因素,位段是不跨平台的,注重可移植的程式應該避免使位段。
列舉顧名思義就是一一枚舉。enum day
;
{}中的內容是列舉型別的可能取值,也叫 列舉常量 。這些可能取值都是有值的,預設從0開始,一次遞增1,當然在定義的時候也可以賦初值。我們可以使用 #define 定義常量,為什麼非要使用列舉?增加**的可讀性和可維護性列舉的優點:
與#define定義的識別符號比較:列舉有型別檢查,更加嚴謹。
防止了命名汙染(封裝)
便於除錯
使用方便,一次可以定義多個常量
聯合是一種特殊的自定義型別這種型別定義的變數也包含一系列的成員,特徵是這些成員公用同一塊空間(所以聯合也叫共用體)。
聯合的成員是共用同一塊記憶體空間的,這樣乙個聯合變數的大小,至少是最大成員的大小。
當最大成員大小不是成員型別最大對齊數的整數倍的時候,就要對齊到最大成員對齊數的整數倍。
列舉類 enum,結構體類 struct
1 列舉型別的值,直觀易於理解,見詞知意。格式 enum 列舉類名 值型別 每個值預設 省略 值型別 以int型資料儲存,從0開始。使用格式 列舉類名 變數 列舉類名.值 namespace demo class program console.readkey 2 結構體類,可以達到整體與區域性的效...
列舉資料型別 struct結構體
列舉通常用來表示一組常量 列舉類似於單項選擇題,只能多軒逸 列舉即可以放在類中也可以放在類外 使用關鍵字enum宣告列舉型別 enum week中間用逗號 半形 間隔,最後一位成員可加可不加 為了區分是最後一位成員,一般不加 列舉預設資料型別為int型,如上 mnday 0 sunday 6 定義乙...
列舉與結構enum
使用 enum 來建立列舉。有如類和其他命名型別,列舉可以有方法。enum rank int let ace rank.ace by gashero let acerawvalue ace.toraw 在如上例子中,原始值的型別是 int 所以可以只指定第乙個原始值。其後的原始值都是按照順序賦值的。...