自定義型別 結構體,列舉,聯合

2021-08-22 08:39:12 字數 4360 閱讀 6842

首先先說一下c語言的資料型別,其框架型別如圖所示:

今天主要說一下結構體,列舉,聯合這三種自定義型別。

1,結構體

1.1 結構體的宣告

結構體是一些值的集合,這些值稱為成員變數,結構體的每個成員可以是不同型別得變數。

(1)結構體的成員:

結構體的成員可以是標量,陣列,指標,甚至是其他結構體。

(2) 結構體的宣告:

struct tag     //struct:結構體關鍵字;tag:結構體標籤

variable_list;

例如:用結構體描述乙個學生如下

struct stu

; //注意末尾的分號一定不能丟

結構體的不完整宣告:

結構體的不完整宣告用於兩個結構體的巢狀使用。

例如:

struct b;

struct a

;struct b

;

因為a的結構體變數裡面有b結構體,b的結構體變數裡面有a結構體,因此無論先宣告誰,裡面都含有未被宣告的結構體變數,因此就可以用結構體的不完整宣告,先宣告乙個結構體的存在,之後再完整地宣告他。

1.2 結構體型別建立

結構體有三種型別:有名結構體,無名結構體,別名結構體。下面分別介紹一下這三種型別的建立。

有名結構體:

(1)定義型別的同時完成變數的定義

struct student  //建立型別

stu; //定義變數stu

(2),先建立型別,再定義變數。

struct student    //建立型別

struct student s; //定義變數

無名結構體:

定義型別的同時完成變數定義

struct               //定義型別為struct(無名)

stu; //定義變數

別名結構體:

typedef struct student  //方便以後查詢,student可省略。

stu; //注意此時的stu為結構體型別的別名,而不為變數

#endif

1.3 結構體變數的定義和初始化

struct point

p1; //宣告型別的同時定義變數p1

struct point p2; //定義結構體變數p2

struct point p3; //初始化:定義變數的同時賦初值

struct stu //型別宣告

;struct stu s = ; //初始化

struct node

n1 = , null}; //結構體巢狀初始化

struct node n2 = , null };//結構體巢狀初始化

1.4 結構體的自引用

在結構體內包含乙個型別為該結構本身的成員就叫結構體的自引用。

自引用方式:

struct node

;typedef struct node

node;

1.5 結構體內存對齊

結構體的對齊規則:

(1)第乙個成員在與結構體變數偏移量為0的位址處。

(2)其他成員要對齊到對齊數的整數倍的位址處。

對齊數:為編譯器預設的對齊數與該成員大小的較小值。(編譯器預設的對齊數在vs環境中中為8,在linux環境中為4)

(3)結構體總大小為最大對齊數的整數倍。

(4)對於巢狀的結構體,巢狀結構體對齊到自己最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數的整數倍。

例如下面 的結構體:

struct 

在vs環境中,編譯器預設對齊數為8,這段**在vs中編譯,其所佔記憶體大小為12個位元組。

具體演算法:第乙個成員是 char型別的乙個陣列,它的對齊數為1,陣列有兩個成員,它占用了前兩個位元組;第二個成員是 int 型的成員,它的對齊數為4,因此它的起始儲存位置應為4的整數倍,前面的a陣列占用了兩個位元組,a陣列後面的兩個位元組浪廢掉,b從第五個位元組的位置開始,占用4個位元組,此時已占用了八個位元組,第三個成員為 char c,它的對齊數為1,因此它放在第九個位元組的位置,第四個成員為 short d,它的對齊數為2,因此它需要從2的倍數處的位元組後開始儲存,因為c在第九個位元組處,因此d需要從第十個位元組的後面開始儲存,所以它存在第11和第12個位元組處,此時四個成員儲存完,共佔了12個位元組的空間,結構體內存對齊規則要求結構體總大小為最大對齊數的整數倍。該結構體中,最大對齊數為4,12正好為4的倍數,所以該結構體共占用記憶體12個位元組。

圖示如下:

總結:結構體的記憶體對齊是拿空間來換取時間的做法(提高了效率,浪廢了空間)

結構體傳參:

我們都知道,函式傳參的時候,引數是需要壓棧的。如果傳遞乙個結構體物件的時候,結構體過大,引數壓棧的系統開銷就會比較大,這樣必然導致效能下降。因此,結構體傳參的時候要傳結構體的位址。

結構體傳參的時候要傳結構體的位址。

1.6 位段,位段計算機大小

位段的宣告和結構體是類似的,有兩個不同:

(1),位段成員必須是 int, unsigned int 或 signed int 。

(2),位段的成員名後面有乙個冒號和乙個數字。

例如:

struct a    //a就是乙個位段型別

像上面的結構體,其成員都是 int 型,所以記憶體開闢時每次開闢4個位元組的空間,即32個bit 位,先開闢4個位元組的空間,第乙個成員a佔兩個位元位,第二個成員佔5個bit 位,第三個成員佔10個,此時一共佔了17個bit 位,32-17=15個bit 位,而最後乙個成員需要佔30個bit 位,顯然15 個已經不夠了,因此需重新開闢 int 型別的4個位元組的空間,所以該結構體一共佔8個bit 位的空間。

位段的記憶體分配:

(1)位段的成員可以是 int, unsigned int, signed int 或者 char(屬於整型家族)型別。

(2)位段的空間上是按照需要以四個位元組(int)或乙個位元組(char)的方式來開闢的。

(3)位段涉及很多不確定因素,位段是不跨平台的,注意可移植的程式應避免使用位段。

位段的跨平台問題:

(1)int 位段是被當成有符號數還是無符號數是不確定的。

(2)位段中最大位的數目不能確定(16位機器最大是16,32位機器最大是32)。

(3)位段中的成員在記憶體中從左向右分配,還是從右向左分配標準未定義。

(4)當乙個結構包含兩個位段,第二個位段成員比較大,無法容納第乙個剩餘的位時,是捨棄剩餘位還是利用,不確定。

位段不存在對齊問題。

跟結構體相比,位段可以達到相同的效果,可以很好地節省空間,但有跨平台問題存在。

2,列舉

列舉型別的定義:

enum ***   //enum是列舉關鍵字,這裡是對性別的列舉

; //注意別丟了分號

enum ***是列舉型別,中的內容是列舉型別的可能取值,也叫列舉常量。這些可能取值都是有值的,預設從0開始,一次增加1,也可在定義時賦初值。

列舉的變數大小為4個位元組。

列舉的優點:

(1)增加了**的可讀性和可維護性。

(2)和#define 定義的識別符號比,列舉有型別檢查,更加嚴謹。

(3)防止了命名汙染

(4)便於除錯

(5)使用方便,一次可定義多個常量。

注意:只能拿列舉常量給列舉變數賦值,才不會出現型別的差異。

3,聯合

聯合也是一種特殊的自定義型別,這種型別定義的變數也包含一系列的成員,特徵是這些成員公用同一塊空間,所以聯合也叫共用體。

union un  //聯合型別的宣告

;union un un; //聯合變數的定義

聯合的特點:聯合的成員是共用同一塊空間的,這樣乙個聯合變數的大小,至少是最大成員的大小。

聯合大小的計算:

**聯合的大小至少是最大成員的大小。

**當最大成員的大小不是最大對齊數的整數倍時,就要對齊到最大對齊數的整數倍處。

自定義型別 結構體 列舉 聯合

結構體 所謂結構體,就是將一大堆值放在一起,建立乙個新的型別,這些成員可以是不同型別的變數。struct tag variable list tag 要求 1.見名知意 2.可以省略 3.不建議省略 member list c語言中,不能為空 variable list 變數列表,可以省略,建議省略...

自定義型別 結構體,列舉,聯合

結構體的宣告 struct tag variable list 例如描述乙個學生 struct stu 分號不能丟特殊的宣告 在宣告結構的時候,可以不完全的宣告。比如 匿名結構體型別 struct x struct a 20 p 警告 編譯器會把上面的兩個宣告當成完全不同的兩個型別。所以是非法的。結...

自定義型別 結構體,列舉,聯合

結構的成員可能具有不同的型別.而且,每個結構成員都有名字,所以為了選擇特定的結構成員需要指明結構成員的名字而不是他的位置.和陣列一樣,結構變數也可以在宣告的同時進行初始化.為了對結構進行初始化,要把待儲存到結構中的值的列表準備好並用花括號括起來.初始化式中的值必須按照結構成員的順序進行顯示,結構初始...