我們知道c語言基本數(shù)據(jù)類型有:
本篇將重點介紹C語言中的自定義類型:結構體扣泊、枚舉、聯(lián)合
undefined結構體
定義:結構是一些值的集合嘶摊,這些值稱為成員變量。結構的每個成員可以是不同類型的變量评矩。
構造:
struct 結構體名
{
結構體所包含的變量或數(shù)組
};
聲明與定義
struct?Stu
{????char?name[20];//名字
????int?age;//年齡
????char?sex[5];//性別
????char?id[20];//學號}叶堆;int?main()
{????struct?Stu?s;????return?0;
}12345678910111213
代碼含義:
struct Stu是結構體類型,相當于int斥杜、float虱颗,不申請空間。Stu是結構體標簽蔗喂。
struct Stu s通過類型創(chuàng)建變量忘渔,申請空間(實例化)。
不完全聲明(匿名結構體類型)
#define?_CRT_SECURE_NO_WARNINGS?1#include?#include?struct{????int?a;????char?b;????float?c;
}x;struct{????int?a;????char?b;????float?c;
}*p;int?main()
{
????p?=?&x;
????system("pause");????return?0;
}123456789101112131415161718192021
上面的代碼執(zhí)行后發(fā)現(xiàn)是有bug的缰儿!?小編推薦一個學C語言/C++的學習裙【 六二七,零一二乖阵,四六四 】宣赔,無論你是大牛還是小白,是想轉(zhuǎn)行還是想入行都可以來了解一起進步一起學習瞪浸!裙內(nèi)有開發(fā)工具儒将,很多干貨和技術資料分享!
這是因為編輯器會把上面兩個聲明當成完全不同的兩個類型对蒲。
正確代碼:
struct?{????int?a;????char?b;????float?c;
}x,*p;int?main()
{
????p?=?&x;
????system("pause");????return?0;
}123456789101112
結構體的訪問
結構體變量訪問成員
結構變量的成員是通過定操作符(.)訪問的钩蚊。點操作符接受兩個操作數(shù)
struct?S?s;?
strcpy(s.name,?"zhangsan");//??使用.訪問name成員s.age?=?20;//使用.訪問age成員1234
結構體訪問指向變量的成員
有時候我們得到的不是一個結構體變量,而是指向一個結構體的指針蹈矮。
struct?S?
{????
????char?name[20];??
????int?age;??
}s;
void?print(struct?S*?ps)?
{????
????printf("name?=?%s???age?=?%d\n",?(*ps).name,?(*ps).age);?
????printf("name?=?%s???age?=?%d\n",?ps->name,?ps->age);????????????????
}12345678910
結構體的自引用
struct?Node?
{????
????int?data;????
????struct?Node*?next;?//指向同類型數(shù)據(jù)的指針};{{123456:0}}
結構體的不完整聲明
struct?B;?//不完整聲明struct?A?
{????
????int?_a;????
????struct?B*?pb;?
};?
struct?B?
{????
????int?_b;????
????struct?A*?pa;?
};123456789101112
結構體的內(nèi)存對齊
為什么存在內(nèi)存對齊
1.平臺原因(移植原因)
不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的砰逻;某些硬件平臺只能在某些地址處取某些特定的數(shù)據(jù),否則拋出硬件異常含滴。
2.性能原因
數(shù)據(jù)結構(尤其是棧)應該盡可能地在自然邊界上對齊诱渤。
原因在于,為了訪問未對齊的內(nèi)存谈况,處理器需要兩次內(nèi)存訪問勺美;而對其的內(nèi)存訪問僅需要一次訪問。
結構體對齊原則
1.第一個成員在與結構體變量偏移量為0 的地址處碑韵。
2.其他成員變量要對齊放到某個數(shù)字(對齊數(shù))的整數(shù)倍的地址處赡茸。對齊數(shù)=編譯器默認的一個對齊數(shù)與該成員大小的較小值。
VS中默認的值是8祝闻,Linux中默認的值是4占卧。
3.結構體總大小為最大對齊數(shù)(每個成員變量都有一個對齊數(shù))的整數(shù)倍遗菠。
4.如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數(shù)的整數(shù)倍處华蜒,結構體的整體大小就是所有最大對齊數(shù)(含嵌套結構體的對齊數(shù))的整數(shù)倍辙纬。
總的來說,結構體的內(nèi)存對齊是拿空間來換取時間的做法
struct?S1
{????char?c1;????int?i;????char?c2;
}printf("%s\n",sizeof(struct?S1));//1+3+4+1+3=12struct?S2?
{????
????char?c1;????
????int?i;?
};?
printf("%d\n",?sizeof(struct?S2));//1+1+2+4=8struct?S3?
{????
????double?d;????
????char?c;????int?i;?
};?
printf("%d\n",?sizeof(struct?S3));//8+1+3+4=16struct?S4?
{????
????char?c1;????struct?S3?s3;????double?d;
}printf("%d\n",?sizeof(struct?S4));//1+7+16+8=32123456789101112131415161718192021222324252627282930
結構體傳參
函數(shù)傳參的時候叭喜,參數(shù)是需要壓棧的贺拣。如果傳遞一個結構體對象的時候,結構體過大捂蕴,參數(shù)壓棧的系統(tǒng)開銷比較大譬涡,所以會導致性能的下降。所以啥辨,結構體傳參的時候涡匀,要傳結構體的地址。
struct?S
{
????char?c1;
????int?i;
????char?c2;
}
void?print(struct?S?*ps)
{????...}
int?main()
{
????print(&s);????return?0;
}12345678910111213141516
undefined位段
與結構體不同的是:
位段的成員必須是 int溉知、unsigned int陨瘩、int 或signed int 、char(屬于整型家族類型)
位段的成員名后邊有一個冒號和一個數(shù)字
位段的分配內(nèi)存
位段的空間是按照需要以1個字節(jié)(char)或4個字節(jié)(int)的方式來開辟的
位段涉及很多不確定因素级乍,位段是不跨平臺的拾酝,注重可移植性的程序應該避免使用位段
struct??S?
{????
????char?_a:3;????
????char?_b:4;????
????char?_c:5;????
????char?_d:4;?
}struct?S?s={0};
s.a=10;
s.b=12;
s.c=3;
s.d=4;printf("%d\n",sizeeof(struct?S));//31234567891011121314
位段的跨平臺問題
int位段被當作有符號數(shù)還是無符號數(shù)無法確定
位段中最大位的數(shù)目不能確定(16位機器最大16,32位機器最大32)
位段中的成員在內(nèi)存中從左向右分配卡者,還是從右向左分配標準未定義蒿囤。
當一個結構包含兩個位段,第二個位段成員比較大崇决,無法容納于第一個位段剩余的位時材诽,時舍棄剩余的位還是利用,這是不確定的恒傻。
跟結構相比脸侥,位段可以達到同樣的效果,但是可以很好的節(jié)省空間盈厘,但是有跨平臺的問題存在
undefined枚舉
定義:顧名思義就是把可能的取值一一列舉
構造:
enum?枚舉名{
標識符[=整型常數(shù)],
標識符[=整型常數(shù)],...標識符[=整型常數(shù)]
}?枚舉變量;{{123456:0}}
如果枚舉沒有初始化, 即省掉”=整型常數(shù)”時, 則從第一個標識符開始, 順
次賦給標識符0, 1, 2, …睁枕。但當枚舉中的某個成員賦值后, 其后的成員按依次
加1的規(guī)則確定其值。
聲明與定義
enum?Color
{
????RED=1,
????GREEN=2;
????BLUE=4;
};enum?Color?clr?=?GREEN;{{1234567:0}}
enum Color是枚舉類型
{}中的內(nèi)容是枚舉類型的可能取值沸手,也叫枚舉常量外遇。這些可能取值都是有值的,默認從0開始契吉,一次遞增1跳仿,當然在定義的時候也可以賦初值。
注意:
枚舉中每個成員(標識符)結束符是”,”, 不是”;”, 最后一個成員可省略”,”捐晶。
初始化時可以賦負數(shù), 以后的標識符仍依次加1菲语。
枚舉變量只能取枚舉說明結構中的某個標識符常量妄辩。
枚舉優(yōu)點
增加代碼可讀性和可維護性
和#define定義的標識符比較,枚舉有類型檢查山上,更加嚴謹眼耀。
防止了命名污染(封裝)
便于調(diào)試
使用方便,一次可以定義多個常量
undefined聯(lián)合(共用體)
定義: 在進行某些算法的C語言編程的時候佩憾,需要使幾種不同類型的變量存放到同一段內(nèi)存單元中畔塔。這種幾個不同的變量共同占用一段內(nèi)存的結構,在C語言中鸯屿,被稱作”共用體”類型結構,簡稱共用體把敢。
構造:
union?共用體名{成員表列
}變量表列;1234
聲明與定義
我們用一段代碼說明寄摆,用結構體判斷編譯器的大小端(面試題)
int?check_sys()
{????union?Un
????{????????int?i;????????char?c;
????}un;
????un.i=1;????return?un.c?;
}int?main()
{????if(check_sys()==1)????????printf("小端\n");????else
????????printf("大端\n");????????return?01234567891011121314151617
聯(lián)合的特點
同一個內(nèi)存段可以用來存放幾種不同類型的成員,但是在每一瞬間只能存放其中的一種修赞,而不是同時存放幾種婶恼。換句話說,每一瞬間只有一個成員起作用柏副,其他的成員不起作用勾邦,即不是同時都在存在和起作用。
共用體變量中起作用的成員是最后一次存放的成員割择,在存入一個新成員后眷篇,原有成員就失去作用。
共用體變量的地址和它的各成員的地址都是同一地址荔泳。
不能對共用體變量名賦值蕉饼,也不能企圖引用變量名來得到一個值。
共用體類型可以出現(xiàn)在結構體類型的定義中玛歌,也可以定義共用體數(shù)組昧港。反之,結構體也可以出現(xiàn)在共用體類型的定義中支子,數(shù)組也可以作為共用體的成員创肥。
共用體變量也可以作為函數(shù)的參數(shù)和返回值
聯(lián)合大小的計算
聯(lián)合的大小至少是最大成員的大小
當最大成員大小不是最大對齊數(shù)的整數(shù)倍的時候,就要對齊到最大對齊數(shù)的整數(shù)倍
union?Un1?
{????
????char?c[5];????
????int?i;?
};?
union?Un2?
{????
????short?c[7];????
????int?i;?
};?
printf("%d\n",?sizeof(union?Un1));?//5*1+3=8printf("%d\n",?sizeof(union?Un2));//7*2+2=16123456789101112
undefined結構體和共同體的結合使用
我們網(wǎng)絡的IP地址是long類型的一段數(shù)字值朋,如: {{19237271:0}}叹侄,但是為了方便讀寫,我們寫成點分十進制形式:192.37.27.1
那么我們怎么轉(zhuǎn)換呢昨登?
union?ip_add
{????unsigned?long?addr;????struct?
????{????????unsigned?char?c1;????????unsigned?char?c2;?
????????unsigned?char?c3;????????unsigned?char?c4;
????}ip;
};int?main()
{????union?ip_addr?my_ip;
????my_ip.addr={{19237271:0}};????printf("%d.%d.%d.%d\n",my_ip.ip.c4,my_ip.ip.c3,my_ip.ip.c2,my_ip.ip.c1);????return?0;
}123456789101112131415161718