結構體的基礎知識,位段,聯合 列舉

2021-08-20 06:55:47 字數 3741 閱讀 8455

結構體屬於聚合資料型別,c語言提供了兩種聚合資料型別,陣列和結構體。

陣列裡面儲存的是同型別的元素的集合,它的每個元素是通過下標引用或者指標間接訪問來選擇的。

結構也是一些值的集合,這些值稱為它的成員,但乙個結構的各個成員可能具有不同的型別,他們需要通過名字去訪問,那個成員都有自己的名字。

1.結構宣告

舉個例子:

struct ******

; //注意這裡必須有乙個分號

這個結構體包含三個成員變數,分別為int型的a,char型的b,float型的c,******為乙個標籤。這個宣告把標籤******和這個成員列表聯絡在一起。注意這只是乙個宣告,並沒有提供變數列表,所以它並未建立任何變數。已經宣告之後的結構體struct ****** 類似於int,double,它相當於乙個結構體型別的識別符號,可以用它來建立結構體變數。比如:

struct ****** x;

struct ****** y[20],*z;

這裡的x,y和z都是同一型別的結構體,可以互相賦值,比如z=&x。

需要注意的是,如果不使用標籤去宣告結構體,必須在結構體後面直接建立結構體變數。

structx;

structy[20],*z;

這裡雖然宣告了兩個結構體型別,而且他們的成員變數一摸一樣,但是它們並不是同一型別的結構體變數,沒有標籤系統會認為這是兩個不同型別的結構體,因此z=&x是非法的。而且這種結構體只能建立一次,無法建立第二個變數。

2.結構成員

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

這裡有乙個更為複雜的例子:

struct complex;
乙個結構體的成員的名字可以和其他結構的成員名字相同,所以這個結構的成員a並不會與struct ****** s 的成員a衝突。

3.結構成員的直接訪問和間接訪問

結構變數的成員是通過點操作符(.)訪問的。點操作符接受兩個運算元,左運算元解釋結構變數的名字,有運算元就是需要訪問的成員的名字。這個表示式的結果就是指定的成員。例如:

struct complex comp;

//假設使用上面的結構體

comp.a; //訪問comp結構體的a成員變數,a是乙個陣列,所以comp.a代表它的陣列名

(comp.s).a; //訪問s結構體的a成員,因為(.)的結合性是從左向右的所以括號可以取消comp.s.a

((comp.sa)[4]).c; //

當你有乙個指向結構體位址的指標p時,要取出結構體成員變數,首先想到的是對指標進行解引用操作,拿出結構體名,然後用點操作符找到結構體成員變數。因為*操作的優先順序低於(.)操作,所以必須加括號(*p).a。但是為了方便起見有乙個更方便的操作符就有了,稱為箭頭操作符:

p->a;

p->b;

p->c;

結構體指標可以這樣訪問結構體成員變數。

4.結構的自引用

在乙個結構內部包含乙個型別為該結構本身的成員:

struct self_ref1;
這種型別的自引用是非法的,因為成員b裡面又包含著乙個同型別的結構體,這樣下去就永無止境,更不知道這個結構體有多大。但如果用指標的方法宣告卻是合法的:

strcut self_ref2;
這個宣告和前面哪個宣告的區別在於成員b是乙個指標而不是乙個結構,編譯器在結構的長度確定之前就已經知道指標的長度。

5.不完整宣告

看下面這個例子:

struct a ;

struct b ;

這是錯誤的,因為在宣告a的時候發現它裡面有結構體b的指標,但是因為結構體b沒有宣告,所以系統找不到b。當你把b放在前面那麼b裡面有結構體a的指標,會產生同樣的錯誤。處理的辦法是建立乙個不完整宣告:

struct b;

struct a ;

struct b ;

在a的上面加上b的不完整宣告,這樣告訴計算機有乙個b型別的結構的,就不會出錯了。

6.結構的初始化

結構的初始化方式和陣列的初始化很相似,乙個位於一堆花括號內部、由逗號分隔的初始值列表可用於結構各個成員的初始化,這些值根據結構成員的順序寫出。如果初始列表的值不夠,剩餘的結構成員將使用預設值進行初始化。

這裡有乙個例子:

struct init_exx = ,

};

位段的成員必須是int、unsigned int和signed int的型別,其次,在成員的後面是乙個冒號和乙個整數,這個整數指定該位段所占用的位的數目。

下面是乙個位段宣告的例子:

struct char;

struct char ch1;

這個位段所佔的空間大小為8個位元組,位段的空間上需要按照以四個位元組或者乙個位元組(字元)的方式來開闢的,6+7=13,13+19>32,所以得再開闢4個位元組。

位段涉及很多不確定因素,所以位段是不跨平台的。

位段不能跨平台的因素:

1.系統的儲存方式不一樣(大小端),從左到右還是從右到左。

2.int被系統當作正號還是負號不確定。

3.32位機器定義的27位,位段,無法在16位機器中執行。

4.當第二個位段成員過大,第乙個位段成員的剩餘空間無法滿足它時,是緊貼著第乙個儲存,還是重新開闢空間,浪費剩餘空間。

總結位段雖然可以很好的節省空間,但是它有跨平台的限制。

列舉就是一一枚舉,把可能的值一一枚舉出來。例如:

enum

color

;

以上定義的enum color是列舉型別,{}內的是列舉型別的可能取值,也叫列舉常量,它們用 「,」隔開,預設值是0、1、2。。。也可以在定義的時候賦初值:

enum color

;enum color s = red; //列舉變數初始賦值只能使用列舉常量

s = 10; //之後的賦值沒有上面這個要求

我們可以用#define來定義常量,為什麼還要使用列舉?

1.列舉的可讀性和可維護性更高。

2.列舉具有型別檢查,更嚴謹。

3.防止命名汙染。

4.便於除錯。

5.使用方便,一次可以定義多個。

聯合也是一種特殊的自定義型別

這種型別定義的變數也包含一些成員,特點就是這些成員使用同一塊空間(所以聯合也叫共用體)。

例如:

union s 

;struct s c; //定義聯合變數

printf("%d",sizeof(c)); //計算聯合變數的大小

上面計算的大小是4,因為變數公用一塊空間,大小至少是最大的成員的大小,並且要是最大對齊數的整數倍。

面試題大小端問題可以用聯合很好的解決。

聯合和結構體的巧妙使用:

//將long型別的ip位址,轉化為點分十進位制的表示形式

union ip_addr

ip;};

union ip_addr my_ip;

my_ip.addr = 176238749;

printf("%d.%d.%d.%d\n",my_ip.ip.c1,my_ip.ip.c2,my_ip.ip.c3,my_ip.ip.c4);

C語言結構體 聯合 位段和列舉知識總結

一 結構體 概述 簡單來說結構體就是一些值的集合,這些值是它的成員,只不過各個成員可能具有不同的型別。結構體的宣告 一種不完全宣告,一種採用重新命名typedef,再就是標準命名。不完全宣告 不宣告結構體的tag 就是匿名宣告。重新命名 將struct student重新命名為student。標準命...

自定義型別(結構體,列舉,聯合,位段)

一.結構體 c語言提供了兩種聚合資料型別,分別為陣列和指標,陣列是相同型別元素的集合,它的每個元素是通過下標引用或指標間接訪問的。結構是不同資料型別的集合,對於結構的訪問不能通過下標去訪問,因為乙個結構的成員可能長度不同。結構並不是它自身成員的陣列,結構變數屬於標量型別。舉例 乙個簡單的結構宣告 s...

結構體,聯合體(共用體),列舉型別,位段,記憶體對齊

struct test 關鍵字 struct,表示其是乙個結構體,後面是乙個可選的標記 test 可以在分號前直接跟變數名,也可以在之後寫為struct test 變數名 strcut test 的作用類似於int 或float的宣告。若寫為 typedef strcut test test 則說明...