IOS開發(fā)之路--C語言構(gòu)造類型
概述
在第一節(jié)中我們就提到C語言的構(gòu)造類型,分為:數(shù)組、結(jié)構(gòu)體、枚舉、共用體,當(dāng)然前面數(shù)組的內(nèi)容已經(jīng)說了很多了,這一節(jié)將會重點說一下其他三種類型。
結(jié)構(gòu)體 枚舉 共用體
結(jié)構(gòu)體
數(shù)組中存儲的是一系列相同的數(shù)據(jù)類型,那么如果想讓一個變量存儲不同的數(shù)據(jù)類型就要使用結(jié)構(gòu)體,結(jié)構(gòu)體定義類似于C++、C#、Java等高級語言中類的定義,但事實上它們又有著很大的區(qū)別。結(jié)構(gòu)體是一種類型,并非一個變量,只是這種類型可以由其他C語言基本類型共同組成。
// // main.c // ConstructedType // // Created by Kenshin Cui on 14-7-18. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #include <stdio.h> //結(jié)構(gòu)體類型Date struct Date{ int year; int month; int day; }; struct Person{ char *name; int age; struct Date birthday;//一個結(jié)構(gòu)體中使用了另一個結(jié)構(gòu)體類型,結(jié)構(gòu)體類型變量聲明前必須加上struct關(guān)鍵字 float height; }; int main(int argc, const char * argv[]) { struct Person p={"Kenshin",28,{1986,8,8},1.72}; //定義結(jié)構(gòu)體變量并初始化,不允許先定義再初始化,例如:struct Person p;p={"Kenshin",28,{1986,8,8},1.72};是錯誤的 printf("name=%s,age=%d,birthday=%d-%d-%d,height=%.2f\n",p.name,p.age,p.birthday.year,p.birthday.month,p.birthday.day,p.height); //結(jié)果:name=Kenshin,age=28,birthday=1986-8-8,height=1.72,結(jié)構(gòu)體的引用是通過"結(jié)構(gòu)體變量.成員名稱" printf("len(Date)=%lu,len(Person)=%lu\n",sizeof(struct Date),sizeof(struct Person)); //結(jié)果:len(Date)=12,len(Person)=32 return 0; }
對于上面的例子需要做出如下說明:
可以在定義結(jié)構(gòu)體類型的同時聲明結(jié)構(gòu)體變量;
如果定義結(jié)構(gòu)體類型的同時聲明結(jié)構(gòu)體變量,此時結(jié)構(gòu)體名稱可以省略;
定義結(jié)構(gòu)體類型并不會分配內(nèi)存,在定義結(jié)構(gòu)體變量的時候才進(jìn)行內(nèi)存分配(同基本類型時類似的);
結(jié)構(gòu)體類型的所占用內(nèi)存大型等于所有成員占用內(nèi)存大小之和(如果不考慮內(nèi)存對齊的前提下);
對第4點需要進(jìn)行說明,例如上面代碼是在64位編譯器下運(yùn)行的結(jié)果(int長度4,char長度1,float類型4),Date=4+4+4=12。但是對于Person卻沒有那么簡單了,因為按照正常方式計算Person=8+4+12+4=28,但是從上面代碼中給出的結(jié)果是32,為什么呢?這里不得不引入一個概念“內(nèi)存對齊”,關(guān)于內(nèi)存對齊的概念在這里不做詳細(xì)說明,大家需要了解的是:在Mac OS X中對齊參數(shù)默認(rèn)為8(可以通過在代碼中添加#pragma pack(8)改變對齊參數(shù)),如果結(jié)構(gòu)體中的類型不大于8,那么結(jié)構(gòu)體長度就是其成員類型之和,但是如果成員變量的長度大于這個對齊參數(shù)那么得到的結(jié)果就不一定是各個成員變量之和了。Person類型的長度之所以是32,其實主要原因是因為Date類型長度12在存儲時其偏移量12不是8的倍數(shù),考慮到內(nèi)存對齊的原因需要添加4個補(bǔ)齊長度,這里使用表格的形式列出了具體原因:
表格具體來源請觀看下面的視頻(注意由于錄制軟件的原因前幾秒不清晰但是不影響分析):
接下來看一下結(jié)構(gòu)體數(shù)組、指向結(jié)構(gòu)體的指針:
// // main.c // ConstructedType // // Created by Kenshin Cui on 14-7-18. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #include <stdio.h> struct Date{ int year; int month; int day; }; struct Person{ char *name; int age; struct Date birthday; float height; }; void changeValue(struct Person person){ person.height=1.80; } int main(int argc, const char * argv[]) { struct Person persons[]={ {"Kenshin",28,{1986,8,8},1.72}, {"Kaoru",27,{1987,8,8},1.60}, {"Rosa",29,{1985,8,8},1.60} }; for (int i=0; i<3; ++i) { printf("name=%s,age=%d,birthday=%d-%d-%d,height=%.2f\n", persons[i].name, persons[i].age, persons[i].birthday.year, persons[i].birthday.month, persons[i].birthday.day, persons[i].height); } /*輸出結(jié)果: name=Kenshin,age=28,birthday=1986-8-8,height=1.72 name=Kaoru,age=27,birthday=1987-8-8,height=1.60 name=Rosa,age=29,birthday=1985-8-8,height=1.60 */ struct Person person=persons[0]; changeValue(person); printf("name=%s,age=%d,birthday=%d-%d-%d,height=%.2f\n", persons[0].name, persons[0].age, persons[0].birthday.year, persons[0].birthday.month, persons[0].birthday.day, persons[0].height); /*輸出結(jié)果: name=Kenshin,age=28,birthday=1986-8-8,height=1.72 */ struct Person *p=&person; printf("name=%s,age=%d,birthday=%d-%d-%d,height=%.2f\n", (*p).name, (*p).age, (*p).birthday.year, (*p).birthday.month, (*p).birthday.day, (*p).height); /*輸出結(jié)果: name=Kenshin,age=28,birthday=1986-8-8,height=1.72 */ printf("name=%s,age=%d,birthday=%d-%d-%d,height=%.2f\n", p->name, p->age, p->birthday.year, p->birthday.month, p->birthday.day, p->height); /*輸出結(jié)果: name=Kenshin,age=28,birthday=1986-8-8,height=1.72 */ return 0; }
結(jié)構(gòu)體作為函數(shù)參數(shù)傳遞的是成員的值(值傳遞而不是引用傳遞),對于結(jié)構(gòu)體指針而言可以通過”->”操作符進(jìn)行訪問。
枚舉
枚舉類型是比較簡單的一種數(shù)據(jù)類型,事實上在C語言中枚舉類型是作為整形常量進(jìn)行處理的,通常稱為“枚舉常量”。
// // main.c // ConstructedType // // Created by Kenshin Cui on 14-7-18. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #include <stdio.h> enum Season{ //默認(rèn)情況下spring=0,summer=1,autumn=2,winter=3 spring, summer, autumn, winter }; int main(int argc, const char * argv[]) { enum Season season=summer; //枚舉賦值,等價于season=1 printf("summer=%d\n",season); //結(jié)果:summer=1 for(season=spring;season<=winter;++season){ printf("element value=%d\n",season); } /*結(jié)果: element value=0 element value=1 element value=2 element value=3 */ return 0; }
需要注意的是枚舉成員默認(rèn)值從0開始,如果給其中一個成員賦值,其它后面的成員將依次賦值,例如上面如果summer手動指定為8,則autumn=9,winter=10,而sprint還是0。
共用體
共用體又叫聯(lián)合,因為它的關(guān)鍵字是union(貌似數(shù)據(jù)庫操作經(jīng)常使用這個關(guān)鍵字),它的使用不像枚舉和結(jié)構(gòu)體那么頻繁,但是作為C語言中的一種數(shù)據(jù)類型我們也有必要弄清它的用法。從前面的分析我們知道結(jié)構(gòu)體的總長度等于所有成員的和(當(dāng)然此時還可能遇到對齊問題),但是和結(jié)構(gòu)體不同的是共用體所有成員共用一塊內(nèi)存,順序從低地址開始存放,一次只能使用其中一個成員,union最終大小由共用體中最大的成員決定,對某一成員賦值可能會覆蓋另一個成員。
// // main.c // ConstructedType // // Created by Kenshin Cui on 14-7-20. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #include <stdio.h> union Type{ char a; short int b; int c; }; int main(int argc, const char * argv[]) { union Type t; t.a='a'; t.b=10; t.c=65796; printf("address(Type)=%x,address(t.a)=%x,address(t.b)=%x,address(t.c)=%x\n",&t,&t.a,&t.b,&t.c); //結(jié)果:address(Type)=5fbff7b8,address(t.a)=5fbff7b8,address(t.b)=5fbff7b8,address(t.c)=5fbff7b8 printf("len(Type)=%d\n",sizeof(union Type)); //結(jié)果:len(Type)=4 printf("t.a=%d,t.b=%d,t.c=%d\n",t.a,t.b,t.c); //結(jié)果:t.a=4,t.b=260,t.c=65796 return 0; }
這里需要重點解釋一個問題:為什么t.a、t.b、t.c輸出結(jié)果分別是4、260、65796,當(dāng)然t.c等于65796并不奇怪,但是t.a前面賦值為'a'不應(yīng)該是97嗎,而t.b不應(yīng)該是10嗎?其實如果弄清這個問題共用體的概念基本就清楚了。
根據(jù)前面提到的,共用體其實每次只能使用其中一個成員,對于上面的代碼經(jīng)過三次賦值最終使用的其實就是t.c,而通過上面的輸出結(jié)果我們也確實看到c是有效的。共用體有一個特點就是它的成員存儲在同一塊內(nèi)存區(qū)域,這塊區(qū)域的大小需要根據(jù)它的成員中長度最大的成員長度而定。由于上面的代碼是在64位編譯器下編譯的,具體長度:char=1,short int=2,int=4,所以得出結(jié)論,Type的長度為4,又根據(jù)上面輸出的地址,可以得到下面的存儲信息(注意數(shù)據(jù)的存儲方式:高地址存儲高位,低地址存儲地位):
當(dāng)讀取c的時候,它的二進(jìn)制是“00000000 00000001 00000001 00000100”,換算成十進(jìn)制就是65796;而經(jīng)過三次賦值后,此時b的存儲就已經(jīng)被c成員的低位數(shù)據(jù)覆蓋,b的長度是二,所以從起始地址取兩個字節(jié)得到的二進(jìn)制數(shù)據(jù)此時是“00000001 00000100”(b原來的數(shù)據(jù)已經(jīng)被c低2位數(shù)據(jù)覆蓋,其實此時就是c的低2位數(shù)據(jù)),換算成十進(jìn)制就是260;類似的a此時的數(shù)據(jù)就是c的低一位數(shù)據(jù)”00000100”,換算成十進(jìn)制就是4。
- iOS中定位當(dāng)前位置坐標(biāo)及轉(zhuǎn)換為火星坐標(biāo)的方法
- 詳解iOS應(yīng)用UI開發(fā)中的九宮格坐標(biāo)計算與字典轉(zhuǎn)換模型
- cisco6509 CatOS 轉(zhuǎn)換為Native IOS實際過程
- ios開發(fā)中時間轉(zhuǎn)換的方法集錦
- iOS開發(fā)之獲取系統(tǒng)相冊中的圖片與視頻教程(內(nèi)帶url轉(zhuǎn)換)
- 解析iOS開發(fā)中的FirstResponder第一響應(yīng)對象
- iOS應(yīng)用開發(fā)中使用NSLocale類實現(xiàn)對象信息的本地化
- iOS 對象屬性詳細(xì)介紹
- iOS獲取網(wǎng)絡(luò)類型的方法匯總
- 使用Reachability類判斷iOS設(shè)備的當(dāng)前網(wǎng)絡(luò)連接類型
- iOS對象指針和基礎(chǔ)數(shù)據(jù)類型的強(qiáng)轉(zhuǎn)詳解
相關(guān)文章
iOS應(yīng)用開發(fā)中導(dǎo)航欄按鈕UIBarButtonItem的添加教程
這篇文章主要介紹了iOS應(yīng)用開發(fā)中導(dǎo)航欄按鈕UIBarButtonItem的添加教程,文中詳細(xì)介紹了使用UINavigationController導(dǎo)航控制器添加的過程,需要的朋友可以參考下2016-02-02ios基于MJRefresh實現(xiàn)上拉刷新和下拉加載動畫效果
本篇文章主要介紹了ios基于MJRefresh實現(xiàn)上拉刷新和下拉加載動畫效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08iOS 指壓即達(dá)集成iOS9里的3D Touch的方法
這篇文章主要介紹了iOS 指壓即達(dá)集成iOS9里的3D Touch的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03