C語(yǔ)言深入探究自定義類型之結(jié)構(gòu)體與枚舉及聯(lián)合
1.結(jié)構(gòu)體
1.1結(jié)構(gòu)體類型的聲明
結(jié)構(gòu)是一些值的集合,這些值稱為成員變量。結(jié)構(gòu)的每個(gè)成員可以是不同類型的變量
這里給大家舉個(gè)列子演示一下:
//定義一個(gè)學(xué)生的結(jié)構(gòu)體 typedef struct Stu { char name[20];//姓名 int age;//年齡 char sex[5];//性別 char id[15];//學(xué)號(hào) }Stu;//分號(hào)不能丟
在這個(gè)結(jié)構(gòu)體里面我們定義了學(xué)生的名字,年齡,性別,學(xué)號(hào)這些變量,這樣的變量就叫做成員變量。
結(jié)構(gòu)的成員可以是標(biāo)量、數(shù)組、指針,甚至是其他結(jié)構(gòu)體。
這里的typedef是將結(jié)構(gòu)體重命名為Stu。
1.2結(jié)構(gòu)的自引用
上面我們說(shuō)到了成員變量也可以為結(jié)構(gòu)體,我們不妨大膽的猜想一下,結(jié)構(gòu)體內(nèi)可以包含一個(gè)類型為自身結(jié)構(gòu)體的成員嗎?
答案當(dāng)然是可以的,不過(guò)有需要我們注意的地方下面給大家用代碼的形式演示一下:
//1.錯(cuò)誤引用 struct Node { int data; struct Node next; }; //2.正確引用 struct Node { int data;//數(shù)據(jù) struct Node* next;//地址 };
對(duì)比上面的代碼正確的代碼比錯(cuò)誤的多一個(gè)' * ',代表傳地址我們來(lái)分析一下錯(cuò)誤的地方,穿了一個(gè)結(jié)構(gòu)體進(jìn)去,那么我們這個(gè)結(jié)構(gòu)體的大小是多少呢,顯然沒(méi)辦法計(jì)算,結(jié)構(gòu)題內(nèi)套一個(gè)結(jié)構(gòu)體,然后這個(gè)結(jié)構(gòu)體又套一起進(jìn)去,類似無(wú)條件遞歸,編譯器也會(huì)報(bào)錯(cuò)。那么我們來(lái)看正確的代碼,
結(jié)構(gòu)體分為兩部分,一部分存放數(shù)據(jù),一部分存放地址,當(dāng)我需要的時(shí)候我們根據(jù)地址找到內(nèi)嵌的結(jié)構(gòu)體,這樣就可以講這些結(jié)構(gòu)體串起來(lái)了,當(dāng)我們?cè)L問(wèn)到最后一個(gè)時(shí),我們只需要給它一個(gè)NULL就停止了,這樣是不是就很完美了呢。
1.3結(jié)構(gòu)體變量的定義和初始化
有了結(jié)構(gòu)體類型怎么定義和初始化結(jié)構(gòu)體變量呢,其實(shí)很簡(jiǎn)單,給大家演示一下:
struct Point { int x; int y; }p1; //1.聲明類型的同時(shí)定義變量p1 struct Point p2; //2.定義結(jié)構(gòu)體變量p2 //3.初始化:定義變量的同時(shí)賦初值 struct Point p3 = { x , y };
1.4結(jié)構(gòu)體內(nèi)存對(duì)齊
我們知道int的大小為4個(gè)字節(jié),char的大小為1個(gè)字節(jié),每個(gè)數(shù)據(jù)類型都有大小,那么結(jié)構(gòu)體大小又是多少呢,該怎么計(jì)算呢?
這里需涉及到一個(gè)知識(shí)點(diǎn)就是內(nèi)存對(duì)齊:
1. 第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。
2. 其他成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。 對(duì)齊數(shù) = 編譯器默認(rèn)的一個(gè)對(duì)齊數(shù) 與 該成員大小的較小值。 VS中默認(rèn)的值為8
3. 結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(每個(gè)成員變量都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。
4. 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整 體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍
文字的形式可能有點(diǎn)抽象,下面用圖來(lái)給大家演示一下:
為什么存在內(nèi)存對(duì)齊?
大部分的參考資料都是如是說(shuō)的:
1. 平臺(tái)原因(移植原因): 不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2. 性能原因: 數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。 原因在于,為了訪問(wèn)未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問(wèn);而對(duì)齊的內(nèi)存訪問(wèn)僅需要一次訪問(wèn)
總體來(lái)說(shuō)就是拿空間換時(shí)間的做法。
那我們?cè)谠O(shè)計(jì)結(jié)構(gòu)體的時(shí)候想要節(jié)省空間就要做到,讓占用空間小的成員盡量集中在一起。
1.5結(jié)構(gòu)體傳參
我們知道在傳參的時(shí)候有兩種方式,傳值和傳址。那么在結(jié)構(gòu)體傳參的時(shí)候我們通常采用結(jié)構(gòu)體地址傳參。
函數(shù)傳參的時(shí)候,參數(shù)是需要壓棧,會(huì)有時(shí)間和空間上的系統(tǒng)開(kāi)銷。
如果傳遞一個(gè)結(jié)構(gòu)體對(duì)象的時(shí)候,結(jié)構(gòu)體過(guò)大,參數(shù)壓棧的的系統(tǒng)開(kāi)銷比較大,所以會(huì)導(dǎo)致性能的
下降。
代碼演示如下:
struct S { int data[1000]; int num; }; struct S s = { {1,2,3,4},1000 };//初始化賦值 void print1(struct S* pc)用struct S*的指針接收 { printf("%d\n", pc->num); } int main() { print1(&s);//傳地址 return 0; }
1.6結(jié)構(gòu)體實(shí)現(xiàn)位段(位段的填充&可移植性)
位段的聲明和結(jié)構(gòu)是類似的,有兩個(gè)不同:
1.位段的成員必須是 int、unsigned int 或signed int 。
2.位段的成員名后邊有一個(gè)冒號(hào)和一個(gè)數(shù)字
如下圖,A就是一個(gè)位段
struct A { int _a:2; int _b:5; int _c:10; int _d:30; };
位段的內(nèi)存分配:
1. 位段的成員可以是 int unsigned int signed int 或者是 char (屬于整形家族)類型
2. 位段的空間上是按照需要以4個(gè)字節(jié)( int )或者1個(gè)字節(jié)( char )的方式來(lái)開(kāi)辟的。
3. 位段涉及很多不確定因素,位段是不跨平臺(tái)的,注重可移植的程序應(yīng)該避免使用位段
位段的跨平臺(tái)問(wèn)題:
1. int 位段被當(dāng)成有符號(hào)數(shù)還是無(wú)符號(hào)數(shù)是不確定的。
2. 位段中最大位的數(shù)目不能確定。(16位機(jī)器最大16,32位機(jī)器最大32,寫(xiě)成27,在16位機(jī) 器會(huì)出問(wèn)題。
3. 位段中的成員在內(nèi)存中從左向右分配,還是從右向左分配標(biāo)準(zhǔn)尚未定義。
4. 當(dāng)一個(gè)結(jié)構(gòu)包含兩個(gè)位段,第二個(gè)位段成員比較大,無(wú)法容納于第一個(gè)位段剩余的位時(shí),是 舍棄剩余的位還是利用,這是不確定的。
2.枚舉
枚舉就是列舉,例如一周有七天可以列舉,三原色可以列舉,性別可以列舉
2.1枚舉類型的定義
enum Color//顏色 { RED,//0 GREEN,//1 BLUE//2 };
這里定義的 enum Color 就是是枚舉類型。
{}中的內(nèi)容是枚舉類型的可能取值,也叫 枚舉常量 。
這些可能取值都是有值的,默認(rèn)從0開(kāi)始,一次遞增1,當(dāng)然在定義的時(shí)候也可以賦初值,RED=1,GREEN=2,BLUE=100,都是可以的。
2.2枚舉的優(yōu)點(diǎn)
1. 增加代碼的可讀性和可維護(hù)性
2. 和#define定義的標(biāo)識(shí)符比較枚舉有類型檢查,更加嚴(yán)謹(jǐn)。
3. 防止了命名污染(封裝)
4. 便于調(diào)試
5. 使用方便,一次可以定義多個(gè)常量
3.聯(lián)合
3.1聯(lián)合類型的定義
聯(lián)合也是一種特殊的自定義類型
這種類型定義的變量也包含一系列的成員,特征是這些成員公用同一塊空間(所以聯(lián)合也叫共用體)。 比如:
//聯(lián)合類型的聲明 union Un { char c; int i; }; //聯(lián)合變量的定義 union Un un; //計(jì)算連個(gè)變量的大小 printf("%d\n", sizeof(un));//計(jì)算出來(lái)結(jié)果為4
3.2聯(lián)合的特點(diǎn)
聯(lián)合的成員是共用同一塊內(nèi)存空間的,這樣一個(gè)聯(lián)合變量的大小,至少是最大成員的大?。ㄒ?yàn)槁?lián)合至少得有能力保存最大的那個(gè)成員)。
上面的例子在聯(lián)合體Un中最大的成員為int占4個(gè)字節(jié),所以聯(lián)合體Un的大小也為4個(gè)字節(jié)。
3.3聯(lián)合大小的計(jì)算
聯(lián)合的大小至少是最大成員的大小。
當(dāng)最大成員大小不是最大對(duì)齊數(shù)的整數(shù)倍的時(shí)候,就要對(duì)齊到最大對(duì)齊數(shù)的整數(shù)倍。
下面兩個(gè)例子中的計(jì)算方法和上面內(nèi)存圖解差不多,大家可以研究一下。
union Un1 { char c[5]; int i; }; union Un2 { short c[7]; int i; }; //下面輸出的結(jié)果是什么? printf("%d\n", sizeof(union Un1));//8 printf("%d\n", sizeof(union Un2));//16
到此這篇關(guān)于C語(yǔ)言深入探究自定義類型之結(jié)構(gòu)體與枚舉及聯(lián)合的文章就介紹到這了,更多相關(guān)C語(yǔ)言結(jié)構(gòu)體內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C++如何實(shí)現(xiàn)在Word文檔中創(chuàng)建列表
這篇文章主要為大家詳細(xì)介紹了介紹如何使用C++在Word文檔中創(chuàng)建編號(hào)列表、項(xiàng)目符號(hào)列表和多級(jí)列表,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-05-05基于C語(yǔ)言構(gòu)建一個(gè)獨(dú)立棧協(xié)程和共享?xiàng)f(xié)程的任務(wù)調(diào)度系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了如何基于C語(yǔ)言構(gòu)建一個(gè)獨(dú)立棧協(xié)程和共享?xiàng)f(xié)程的任務(wù)調(diào)度系統(tǒng),文中的示例代碼講解詳細(xì),需要的可以參考下2024-02-02VSstudio中scanf返回值被忽略的原因及解決方法(推薦)
這篇文章主要介紹了VSstudio中scanf返回值被忽略的原因及其解決方法,scanf返回值被忽略,接下來(lái)我就告訴大家該如何解決這個(gè)問(wèn)題,需要的朋友可以參考下2022-09-09C語(yǔ)言中的函數(shù)指針基礎(chǔ)學(xué)習(xí)教程
這篇文章主要介紹了C語(yǔ)言中的函數(shù)指針基礎(chǔ)學(xué)習(xí)教程,包括函數(shù)指針作為參數(shù)來(lái)傳遞等重要知識(shí),需要的朋友可以參考下2016-04-04C++函數(shù)重載、隱藏與覆蓋重寫(xiě)的精通指南
這篇文章主要給大家介紹了關(guān)于C++函數(shù)重載、隱藏與覆蓋重寫(xiě)的相關(guān)資料,這幾個(gè)名詞看著好像很像,不過(guò)其實(shí)一樣都不一樣,本文通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-01-01Cocos2d-x中使用CCScrollView來(lái)實(shí)現(xiàn)關(guān)卡選擇實(shí)例
這篇文章主要介紹了Cocos2d-x中使用CCScrollView來(lái)實(shí)現(xiàn)關(guān)卡的選擇實(shí)例,本文在代碼中用大量注釋講解了CCScrollView的使用,需要的朋友可以參考下2014-09-09常用Hash算法(C語(yǔ)言的簡(jiǎn)單實(shí)現(xiàn))
下面小編就為大家?guī)?lái)一篇常用Hash算法(C語(yǔ)言的簡(jiǎn)單實(shí)現(xiàn))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09