1.4 複合數據類型和枚舉類型

逗比:嗚啦啦啦啦啦~嗚啦啦啦拉拉~各位小夥伴們大家好呀,歡迎來到暴走大……
棒槌:CUT!
逗比:哈?怎麼了?第五季的出場不夠帥?
棒槌:我說你拿錯劇本了吧……
逗比:哦?是嗎?啊呀!!!還真是咧,這是聖誕老王的劇本……
棒槌:我說你是來逗比的嗎?
逗比:咳咳,明明是你昨天嫌我太正經,要我逗比一點的,一點都不體諒人家的辛苦。
棒槌:本來就是,你去看看你同時更新那個操作系統的文章,簡直就是領導講話,一點都不好玩。
逗比:你也拜託,那個系列只不過是我的學習筆記,又不是教程,幹嘛要弄得那麼逗比。
棒槌:可是我也想學啊,你不弄逗比點我看不進去學不會。
逗比:行行行,自己棒槌還賴我,你也別那麼着急去學操作系統內核,C語言的功底特別重要,你先好好跟着我把C語言搞明白的再想別的哈。
棒槌:說誰棒槌呢,你個逗比,趕緊的,我一年前的問題你還沒解決呢,後來就跑得沒影了,現在該給我們介紹了吧。
逗比:好的好的,雖然我一年沒來,不過你的問題我還是記得的,你當時是問,如果我想表示一個學生的基本信息,那用基本數據類型會很不方便,那麼我們應該怎麼辦。
棒槌:記得都不說早點回來給我解答,一點都沒有當老師的責任感……
逗比:我們就拿一個學生的信息表示來舉例,一個學生,他應該有姓名、性別、年齡、學號等的信息,由於姓名這一屬性需要用到字符串,這個我們後面再談,所以呢,我們目前就僅僅來實現學校、性別和年齡這三個屬性。
棒槌:又避開話題……算了,你繼續說吧。
逗比:首先來說性別,性別這一屬性當然可以用整型,你可以規定0表示男,1表示女,但是,如果出於某種原因……
棒槌:什麼原因?
逗比:什麼原因?比如說這哥們突然棒槌了,或者那一天出去關門的時候沒注意,把自己腦袋給夾了……之類的。
棒槌:(吐血)
逗比:這個時候,如果你給性別這個屬性賦值個2呀3呀或者100000之類的,程序其實是不會有任何問題的,但是這個程序要是運行出來肯定就比較傻了,因爲你這第三個性別第四個性別就算能理解,這第幾十萬個性別貌似就有點說不過去了,但是,由於你使用整型,對這個變量的取值是沒有做特殊要求的,這就很容易讓人給它賦一個沒有意義的值。
棒槌:真逗,你以爲讀你程序的人都是棒槌啊?
逗比:這種事情誰能說得準呢,你看,現在不就有個棒槌在看我的程序。
棒槌:誰呀?誰呀?
逗比:好了,所以,我們還是應該更加明示一下這個變量具體表示的意思,雖然對於計算機來說它就是整型,但是,我們應當讓提示一下讀程序的人(這個人很有可能就是你自己,因爲寫多了的話肯容易把之前的忘掉)這個變量其實表示的是什麼,所以,我們就給整型再起一個別名,這樣做的好處是,提示程序員它實際表示的是什麼,與此同時,計算機會仍然把它當做整型來對待。
typedef int Sex;
Sex stu_sex = 0;
逗比:相當於給int又起了個名字叫Sex,所以你寫Sex stu_sex其實就相當於寫了int stu_sex,但這樣意義更加明確,至少程序員知道這個變量是表示性別的了。
棒槌:可是就算是這樣,還是沒有解決你剛說的問題啊,我還是不能從這個Sex直接判斷出來我是應該賦值0呢還是1呢還是2呢還是10000呢……
逗比:沒錯,這樣做確實還沒有解決問題,我們僅僅是知道用它表示性別,但還是不知道到底用哪兩個數來表示男女,所以,繼續給出解決方案,這就是枚舉類型。
棒槌:美劇?美劇不好看啦,我喜歡韓劇。
逗比:我還日劇呢,拜託你聽清楚好不好,是枚舉,不是美劇,我的普通話應該很標準的吧。
棒槌:切~還說自己是逗比呢,一點都不懂美式幽默……
逗比:自己講了個冷笑話還好意思說我。好了,繼續說,我們剛纔是給數據類型起了別名,而枚舉類型相當於連同數值也起了別名,我們可以給出某一枚舉類型的有限個取值,而至於每個取值究竟對應哪個整數,那就是我們自己說了算了。
棒槌:不懂,完全不懂。
逗比:好吧,不懂沒關係,來看個例子吧,這次我就不用性別了,我用一年四季來舉一個栗子。
棒槌:栗子!
逗比:喂!你是花栗鼠嗎?還隨身帶栗子……到底誰是來逗比的啊……
enum season {
    seasonSpring = 1,
    seasonSummer = 2,
    seasonAutumn,
    seasonWinter
};
enum season s1 = seasonSummer;

棒槌:噢噢噢噢,我看明白了,你創造了一個新的類型叫season,然後呢,這個類型只有這4個取值是不是啊。
逗比:額……其實呀,你的這種理解是有道理的,因爲很多教材上就是這麼來解釋枚舉的,但是吧,還真不太對。
棒槌:教材上的不對,你的就對,哪來的自信啊。
逗比:我沒說這種解釋不對,因爲通常針對於新手來說,這樣可以幫助理解,但是,這種理解其實是更接近於程序員的思維上的理解,換句話說,你以後在寫程序的時候確實可以這麼認爲,但是,我還是希望咱們大家能夠明白底層的實現,也就是說,我們要學會用計算機的思維來想這件事情,如果用計算機的方式來說的話,那剛纔這個解釋就真的不對了。
棒槌:好吧,雖然你剛纔說教材錯了這一點我很鄙視你,不過你還是繼續講吧。
逗比:明明被我說動了……口是心非的傢伙。好吧,我繼續來說。其實呢,枚舉類型並不能算是一種新的類型,它本質上還是整型,所以假如說你給s1賦值一個8也是完全沒問題的,你用printf()來打印也一樣出整數,只不過,程序員在給它賦值的時候,可以直接寫seasonSpring,而並不需要去管這個取值對應的到底是哪個整數了。棒槌你聽懂沒?
棒槌:基本上算是明白了吧,不過還有一個問題,你看你給春天指定了一個1,給夏天指定了一個2,後面那倆你沒指定數啊,那應該是多少呢?
逗比:這個問題問的相當好!雖然說我們可以給每個枚舉的取值取一個對應的數值,但是,如果我們不寫的話是有默認值的,就比如說上面,我們給夏天指定了2,秋天沒有寫,就會默認3,冬天就會默認4。而如果我們全部都沒有寫的話,最開頭的一個就會默認0。
棒槌:那如果這麼說的話,seasonSummer後面的2其實也可以不用寫的吧。
逗比:沒錯。
棒槌:好了,會了。
逗比:真會了?
棒槌:那可不,我這麼有才華,智商這麼高~
逗比:那我考考你,敢不敢?
棒槌:放馬過來吧~
逗比:稍微一不注意就開始嘚瑟,看我讓你個棒槌現原形。那我問你,既然我已經給枚舉名起名是season了,它的成員爲什麼還要用season前綴,我直接寫spring,summer這樣不可以麼?
棒槌:這個啊……這個嘛……我當然知道了,因爲這樣可以顯得高大上!
逗比:棒槌~你寫程序是爲了裝X啊。不會就說不會,以後不要還沒學完就開始嘚瑟。
棒槌:行行行,我錯了,你趕緊講吧。
逗比:這裏是一個明明規範,這裏我們一年四季可能大家都不會理解成別的,但是,更多的時候,只是給你一個枚舉取值,我們是不知道它屬於哪個類型中的,因此,把枚舉名作爲取值的前綴更加方便我們閱讀和使用。另外要說明的一點是,enum XXX {...}這整個都是一個類型,你是可以給後面直接聲明變量的,比如說
enum Sex {
    sexMale,
    sexFemale
} s1, s2;
所以,分號是結束標記,即便你後面沒有跟變量,也得有分號,這個千萬別忘了。還有一個要說的就是,enum season整體作爲一個類型名稱,不能光寫一個season。
棒槌:麻煩死了~~~我覺得每次都寫enum太麻煩了,看着還累,你看看我這麼着行不行。
typedef enum season Season;
Season s4 = seasonSpring;
逗比:哎喲喂~我說真的難得你能正經一回。非常非常不錯,就用我剛纔講的typedef重新命名一下就可以去掉這個enum關鍵字。順便說一下,寫一個enum的聲明,然後用typedef,這兩句可以合二爲一來寫,就像這樣:
typedef enum season {
    seasonSpring,
    seasonSummer,
    seasonAutumn,
    seasonWinter
} Season;
我們把enum的主體嵌套在typedef中,這樣分號前的就不是變量了,而是重命名後的名稱,這樣你寫enum season或者寫Season都可以。當然,還有一種更加簡潔的方法,就是使用匿名枚舉,所謂匿名就是沒有名字,用整個主體作爲類型聲明,再配合上typedef,這也是我建議大家的寫法,以後枚舉類型都可以這麼去寫:
typdef enum {
    sexMale,
    sexFemale
} Sex;
順便一提,使用typedef重命名後的名字,一般用大駝峯,首字母大寫,這也是一種命名規範。
棒槌:O了,這個我完全懂了,繼續吧。
逗比:好的,解決了性別問題,年齡和學號用整型就可以了,接下來的任務就是怎麼把它們結合一起,以前的方法是用三個變量分別表示,但這樣很麻煩,操作起來還容易出錯,並且,這些變量應該是綁定性的,不是分散的,它們應該統一處理,由此我們引入了結構體,和枚舉非常類似,但它屬於一個複合類型,由於剛纔我們有了枚舉類型的功底了,這裏我就不再進行變形的演變,直接寫出最終版:
typedef enum {
    sexMale,
    sexFemale
} Sex;
typedef struct {
    int number;
    int age;
    Sex sex;
} Student;
注意結構體成員以分號結尾,不像枚舉那樣用逗號隔開。結構體的三個成員是綁定的,我們每定義一個Student類型變量,就相當於定義了三個變量,下面是一個舉例:
Student s1; // 定義變量
s1.number = 1; // 用點運算符訪問成員
s1.age = 21;
s1.sex = sexMale;
無論是讀取還是寫入這個變量的成員,都用點運算符(就是英文的句號)。用點運算相當於操作了這個結構體變量的某一部分,當然它也可以整體操作,比如:
Student s2 = s1; // 整體賦值
結構體中可以嵌套枚舉,自然,結構體裏也可以嵌套結構體,比如說:
struct s1 {
    struct {
        int s11, s12;
    } s1;
    int s2;
};
struct s1 va1; // 定義變量
va1.s1.s11 = 0; // 給成員的成員賦值
va1.s1.s12 = 2;
va1.s2 = 8;

好啦,多的栗子不舉了,棒槌你應該會了吧。
棒槌:舉栗子!
逗比:這人絕對絕對是花栗鼠變得,我可告訴你,結構體你學這麼快,不代表你後面學得快,下節課我要講指針,這可是幾乎所有剛入門的小夥伴都頭疼的東西,你可要做好準備!
棒槌:就我還怕這個?憑我的聰明才智,看我分分鐘給你搞定!栗子栗子栗子!
逗比:哎~~哎~~你那栗子不打算分我點啊,我給你講這麼半天都不說慰問我一下。哎~~別跑~~




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章