我們在前邊學資料型別的時候,主要是字元型、整型、浮點型等基本型別,而學陣列的時候,陣列的定義要求陣列元素必須是相同的資料型別。在實際應用中,有時候還需要把不同型別的資料組成乙個有機的整體來處理,這些組合在乙個整體中的資料之間還有一定的聯絡,比如乙個學生的姓名、性別、年齡、考試成績等,這就引入了復合資料型別。復合資料型別主要包含結構體資料型別、共用體資料型別和列舉體資料型別。首先我們回顧一下上面的例程,我們把 ds1302 的 7 個位元組的時間放到乙個緩衝陣列中,然後把陣列中的值稍作轉換顯示到液晶上,這裡就存在乙個小問題,ds1302 時間暫存器的定義並不是我們常用的「年月日時分秒」的順序,而是在中間加了乙個位元組的「星期幾」,而且每當我要用這個時間的時候都要清楚的記得陣列的第幾個元素表示的是什麼,這樣一來,一是很容易出錯,二是程式的可讀性不強。當然你可以把每乙個元素都定乙個明確的變數名字,這樣就不容易出錯也易讀了,但結構上卻顯得很零散了。於是,我們就可以用結構體來將這一組彼此相關的資料做乙個封裝,它們既組成了乙個整體,易讀不易錯,而且可以單獨定義其中每乙個成員的資料型別,比如說把年份用 unsigned int 型別,即 4 個十進位制位來表示顯然比 2 位更符合日常習慣,而其它的型別還是可以用 2 位來表示。結構體本身不是乙個基本的資料型別,而是構造的,它每個成員可以是乙個基本的資料型別或者是乙個構造型別。
結構體既然是一種構造而成的資料型別,那麼在使用之前必須先定義它。
宣告結構體變數的一般格式如下:
struct 結構體名 結構體變數名 1, 結構體變數名 2, ... 結構體變數名 n;
這種宣告方式是在宣告結構體型別的同時又用它定義了結構體變數,此時的結構體名是可以省略的,但如果省略後,就不能在別處再次定義這樣的結構體變數了。這種方式把型別定義和變數定義混在了一起,降低了程式的靈活性和可讀性,因此我們並不建議採用這種方式,而是推薦用以下這種方式:
struct 結構體名 ;
struct 結構體名 結構體變數名 1, 結構體變數名 2, ... 結構體變數名 n;
為了方便大家理解,我們來構造乙個實際的表示日期時間的結構體。
structstime
;struct
stime buftime;
struct 是結構體型別的關鍵字,stime 是這個結構體的名字,buftime 就是定義了乙個具體的結構體變數。那如果要給結構體變數的成員賦值的話,寫法是
buftime.year = 0x2013;
buftime.mon = 0x10;
陣列的元素也可以是結構體型別,因此可以構成結構體陣列,結構體陣列的每乙個元素都是具有相同結構型別的結構體變數。例如我們前邊構造的這個結構型別,直接定義成 struct stime buftime[3];就表示定義了乙個結構體陣列,這個陣列的 3 個元素,每乙個都是乙個結構體變數。同樣的道理,結構體陣列中的元素的成員如果需要賦值,就可以寫成
buftime[0].year = 0x2013;
buftime[0].mon = 0x10;
乙個指標變數如果指向了乙個結構體變數的時候,稱之為結構指標變數。結構指標變數是指向的結構體變數的首位址,通過結構體指標也可以訪問到這個結構變數。
結構指標變數宣告的一般形式如下:
struct stime *pbuftime;
這裡要特別注意的是,使用結構體指針對結構體成員的訪問,和使用結構體變數名對結構體成員的訪問,其表示式有所不同。結構體指針對結構體成員的訪問表示式為
pbuftime->year = 0x2013;
或者是(*pbuftime).year = 0x2013;
很明顯前者更簡潔,所以推薦大家使用前者。共用體也稱之為聯合體,共用體定義和結構體十分類似,我們同樣是推薦以下形式:
union 共用體名 ;
union 共用體名 共用體變數;
共用體表示的是幾個變數共用乙個記憶體位置,也就是成員 1、成員 2……成員 n 都用乙個記憶體位置。共用體成員的訪問方式和結構體是一樣的,成員訪問的方式是:共用體名.成員名,使用指標來訪問的方式是:共用體名->成員名。
共用體可以出現在結構體內,結構體也可以出現在共用體內,在我們程式設計的日常應用中,最多應用是結構體出現在共用體內,例如:
unionhalf;
} number;
這樣將乙個結構體定義到乙個共用體內部,我們如果採用無符號整型賦值的時候,直接呼叫 value 這個變數,同時,我們也可以通過訪問或賦值給 first 和 second 這兩個變數來訪問或修改 value 的高位元組和低位元組。
這樣看起來似乎是可以高效率的在 int 型變數和它的高低位元組之間切換訪問,但請回想一下,我們在介紹資料指標的時候就曾提到過,多位元組變數的位元組序取決於微控制器架構和編譯器,並非是固定不變的,所以這種方式寫好的程式**在換到另一種微控制器和編譯環境後,就有可能是錯的,從安全和可移植的角度來講,這樣的**是存在隱患的,所以現在諸多以安全為首要訴求的 c 語言程式設計規範裡乾脆直接禁止使用共用體。我們雖然不禁止,但也不推薦你用,除非你清楚的了解你所使用的開發環境的實現細節。
共用體和結構體的主要區別如下:在實際問題中,有些變數的取值被限定在乙個有限的範圍內。例如,乙個星期從周一到週日有 7 天,一年從 1 月到 12 月有 12 個月,蜂鳴器有響和不響兩種狀態等等。如果把這些變數定義成整型或者字元型不是很合適,因為這些變數都有自己的範圍。c 語言提供了一種稱為「列舉」的型別,在列舉型別的定義中列舉出所有可能的值,並可以為每乙個值取乙個形象化的名字,它的這一特性可以提高程式**的可讀性。
列舉的說明形式如下:
enum 列舉名;
enum 列舉名 列舉變數;
列舉的說明形式中,如果沒有被初始化,那麼「=整型常數」是可以被省略的,如果是預設值的話,從第乙個識別符號順序賦值 0、1、2„„,但是當列舉中任何乙個成員被賦值後,它後邊的成員按照依次加 1 的規則確定數值。
列舉的使用,有幾點要注意:
復合資料型別
復合資料型別 作用 封裝資料 多種不同型別資料存放在一起 應存放在全域性,在訪問結構體中的變數時,應用stu.id stu.name 初始化的方式 在對陣列進行初始化時 strcpy stu.name,zhangsan 在對指標進行初始化時 char name 對name進行初始化 stu.name...
復合資料型別
一 struct結構體 封裝資料 存放多種不同的資料型別 struct的宣告放在全域性區 1.宣告和定義 宣告 struct student struct student stu array 3 int i for i 0 i 3 i for i 0 i 3 i include struct stu...
復合資料型別
結構體 作用 封裝資料 把多種不同的資料型別放在一起 注意 一般放在全域性 分號不能省略。結構體變數用點訪問 結構體指標用 訪問 初始化 靜態初始化 動態初始化 使用注意事項 給結構體中的陣列成員賦值時,不能直接將字串賦給陣列名,可以使用strcpy函式 給結構體中的指標變數成員賦值時,要先給指標分...