C語言自定義類型全解析
前言
初學(xué)C語言
我們先接觸的都是內(nèi)置的類型
比如說int char short float double long等等
這一期就來聊一聊自定義類型的知識
結(jié)構(gòu)體類型
首先我們要知道什么是結(jié)構(gòu)體
結(jié)構(gòu)體就是各種值集合
這些值被稱作結(jié)構(gòu)體成員,這些成員可包括各種不同的類型
struct tag //這里的struct是結(jié)構(gòu)體的關(guān)鍵字,tag是結(jié)構(gòu)體標(biāo)簽,也就是結(jié)構(gòu)體的名稱 { number - list; //結(jié)構(gòu)體成員列表 }veriable-list; //結(jié)構(gòu)體的變量
結(jié)構(gòu)體的聲明
如果結(jié)構(gòu)體的標(biāo)簽是student,我拿student來舉例子
結(jié)構(gòu)體的完整聲明
struct Student { char name[20];//姓名 char sex;//性別 int age;//年齡 int num;//學(xué)號 }; //這里的分號不能丟
結(jié)構(gòu)體的不完全聲明(匿名結(jié)構(gòu)體類型)
struct { int a; char b; double c; }s; //這s不能省略
匿名結(jié)構(gòu)體的特點(diǎn)就是沒有結(jié)構(gòu)體標(biāo)簽
但這樣寫用戶使用時只能使用一次,也就是說只能在結(jié)構(gòu)體聲明時就定義變量
因?yàn)槟阏也坏浇Y(jié)構(gòu)體標(biāo)簽,就相當(dāng)于找不到門牌號一樣,無法再對其定義一個變量
結(jié)構(gòu)體變量的定義與初始化
結(jié)構(gòu)體的定義大致分為三種情況
<1>結(jié)構(gòu)體聲明的同時定義
struct Student { char name[20];//姓名 char sex[20];//性別 int age;//年齡 }s={"zhangsan","nan",20};
<2>結(jié)構(gòu)體先聲明,再定義
#include<stdio.h> struct Student { char name[20];//姓名 char sex;//性別 int age;//年齡 int num;//學(xué)號 }; int main() { struct Student s = { "zhangsan",'w',20,111 }; return 0; }
<3>匿名結(jié)構(gòu)體定義
struct { char name[20];//姓名 char sex[20];//性別 int age;//年齡 } s = { "zhangsan","nan",20};
注意:結(jié)構(gòu)體初始化與數(shù)組相同,都必須整體進(jìn)行賦值。
結(jié)構(gòu)體的自引用
struct Node //初始話鏈表 { int a; struct Node next; };
結(jié)構(gòu)體的自引用就是結(jié)構(gòu)體再套用自己
學(xué)過數(shù)據(jù)結(jié)構(gòu)的朋友應(yīng)該知道這是初始化鏈表
不過這一個代碼有問題的
問題在于無法求出這個結(jié)構(gòu)體的大小,不清楚這個結(jié)構(gòu)體有多大,因?yàn)闊o法求出自引用的結(jié)構(gòu)體有多大
所有自引用的結(jié)構(gòu)體要用指針來訪問
struct Node //初始話鏈表 { int a; struct Node* next; };
故就可以通過指針來訪問每一個結(jié)點(diǎn)
結(jié)構(gòu)體的訪問
當(dāng)結(jié)構(gòu)體定義且變量初始化完成后,就可以通過操作符來訪問變量中的成員
當(dāng)然,這里給出了兩個操作符
分別是? .操作符和 -> 操作符
當(dāng)使用結(jié)構(gòu)體變量時,就用點(diǎn)操作符,當(dāng)訪問結(jié)構(gòu)體指針變量就用箭頭操作符
(1)通過結(jié)構(gòu)體變量進(jìn)行訪問:
printf("%s\n",s.name);
(2)通過結(jié)構(gòu)體指針進(jìn)行訪問:
printf("%s\n",ps->name);
結(jié)構(gòu)體的傳參
函數(shù)的調(diào)用有時候需要傳一些參數(shù)
參數(shù)的類型可以是不同的類型,可以是數(shù)組,也可以是指針
同樣結(jié)構(gòu)體的傳參也可通過傳結(jié)構(gòu)體或者傳指針
傳結(jié)構(gòu)體
#include<stdio.h> struct tag { int a; char b[20]; }s1 = { 100,"abcdef" }; void print() { printf("%d", s1.a); } int main() { print(s1); return 0; }
傳地址
#include<stdio.h> struct tag { int a; char b[20]; }s2 = { 100,"abcdef" }; void print(struct tag*s2) { printf("%d", s2->a); } int main() { print(&s2); return 0; }
我們要知道函數(shù)傳參是形參就是實(shí)參的臨時拷貝
參數(shù)是要壓棧的(向系統(tǒng)申請空間),既然是臨時拷貝,就會再次再棧上開辟空間,當(dāng)實(shí)參足夠大時,顯然會浪費(fèi)一定的空間和時間
相比較與傳結(jié)構(gòu)體,傳指針會更好?
結(jié)構(gòu)體的內(nèi)存對齊(強(qiáng)烈建議觀看)
在另外一篇文章詳細(xì)講過——C語言結(jié)構(gòu)體中內(nèi)存對齊的問題理解
位段
可能有人沒有聽過什么是位段
位段的結(jié)構(gòu)類型跟結(jié)構(gòu)體有些類似可以類似結(jié)構(gòu)體去學(xué)習(xí)
也可以說
位段是結(jié)構(gòu)體特殊的實(shí)現(xiàn)
位段的聲明
相較于結(jié)構(gòu)體,位段的聲明有兩點(diǎn)不同
<1>規(guī)定位段的成員的必須是int,unsigned int ,signed int (但是寫成char類型也沒什么大的問題)
<2>位段的成員后面有一個冒號和一個數(shù)字
struct A //位段的聲明 { int _a : 2; int _b : 5; int _c : 10; int _d : 30; };
位段的內(nèi)存管理
#include<stdio.h> struct A { int a : 2; int b : 5; int c : 10; int d : 30; }; int main() { printf("大小是%d字節(jié)", sizeof(struct A)); return 0; }
為什么位段的大小是八個字節(jié)呢?
成員內(nèi)包含的數(shù)字代表的是這個成員需要利用的內(nèi)存,單位是bit。
位段成員申請內(nèi)存時都是以四個字節(jié)或者一個字節(jié)單位(當(dāng)成員是char類型時)
int a : 2; //申請4個字節(jié),也就是32個bit位,利用兩個還剩30個
int b : 5; //利用5個,還剩25個
int c : 10; //利用10個,還剩15個
int d : 30; //這里的十五不夠,所以再申請了4個字節(jié)
最終的結(jié)果就是八字節(jié)
但問題是,變量d利用的空間是留下的15個bit加上重新申請的空間呢
這個結(jié)果在不同的環(huán)境的結(jié)果是不同的,所以位段的跨平臺性比較差
位段使用的前提是你知道存儲的內(nèi)存大概有多大
就比如說年齡
十個bit位0111111111,最大值就可以達(dá)到1023
就不需要再申請一次利用一個int類型的空間大小
這就達(dá)到了節(jié)省內(nèi)存的作用,存在即合理
位段的應(yīng)用?
struct A { char a : 3; char b : 4; char c : 5; }; main() { struct A s = { 0 }; s.a = 10; s.b = 12; s.c = 3; return 0; }
位段的跨平臺性
1.int位段被當(dāng)成有符號數(shù)還是無符號數(shù)是不確定的,有時候系統(tǒng)會自動轉(zhuǎn)化為無符號整形。
2.位段中最大位的數(shù)目不能確定。(因?yàn)樵谠缙诘?6位機(jī)器int最大16,而32位機(jī)器int最大32)
3.位段中的成員在內(nèi)存中從左向右分配,還是從右向左分配標(biāo)準(zhǔn)尚未定義。
意思當(dāng)內(nèi)存一個字節(jié)00000000,存入01010,可能會出現(xiàn)00001010或者01010000
4.當(dāng)一個結(jié)構(gòu)包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是 舍棄剩余的位還是利用,這是不確定的。
?枚舉類型
枚舉類型適用于可以一一列舉的類型
比如說星期、性別
枚舉類型的定義
enum Day //星期 { //枚舉的可能取值 Mon, Tues, Wed, Thir, Fri, Sta, Sun };
enum Sex //性別 { MALE,//0 FEMALE,//1 SECRET//2 };
枚舉類型是有初始值的
如果你沒賦予它初始值,就會默認(rèn)從零開始,依次加一
枚舉類型賦予初始值
#include<stdio.h> enum Sex //性別 { MALE = 4, FEMALE=10, SECRET// }; main() { printf("%d %d %d", MALE,FEMALE,SECRET); return 0; }
可以看到,其實(shí)默認(rèn)的值是可以改的
當(dāng)某個成員被賦予某個值的時候,后續(xù)的成員就在此基礎(chǔ)上加一
枚舉類型的優(yōu)點(diǎn)
1.相較于數(shù)字,枚舉增加代碼的可讀性和可維護(hù)性
2.和#define定義的標(biāo)識符比較枚舉有類型檢查,更加嚴(yán)謹(jǐn)。
3.防止了命名污染(封裝)
4.便于調(diào)試
5.使用方便,一次可以定義多個常量
聯(lián)合體類型
聯(lián)合體類型也叫共用體
聯(lián)合體的定義
union Un { int a; char b; };
union是聯(lián)合體關(guān)鍵字,Un是聯(lián)合體的標(biāo)簽
聯(lián)合體的特點(diǎn)
共用體,顧名思義,這里的共用就是公用內(nèi)存
內(nèi)存的也可被折疊
#include<stdio.h> union Un { char c; int i; }; int main() { union Un u = {0}; printf("%d\n", sizeof(u)); printf("%p\n", &u); printf("%p\n", &(u.c)); printf("%p\n", &(u.i)); return 0; }
他們有相同的地址
c和i存放在同一塊內(nèi)存空間上,修改c或者i都會影響到另一個成員。
?聯(lián)合體內(nèi)存大小的計(jì)算
<1>聯(lián)合體內(nèi)存大小是最大成員的大小
<2>最大成員的大小如果不是最大對齊數(shù)的整數(shù)倍,就會對齊到最大對齊數(shù)的整數(shù)倍
(聯(lián)合體也存在內(nèi)存對齊)
#include<stdio.h> union Un1 { char c[5]; int i; }; //Un1成員最大成員大小5,最大對齊數(shù)是4,所以Un1的大小是8; union Un2 { char c[7]; int i; }; //Un2成員最大成員大小7,最大對齊數(shù)是4,所以Un2的大小是8; int main() { printf("%d\n", sizeof(union Un1)); printf("%d\n", sizeof(union Un2)); return 0; }
到此這篇關(guān)于C語言自定義類型全解析的文章就介紹到這了,更多相關(guān)C語言 自定義類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)Dijkstra算法的示例代碼
迪杰斯特拉算法(Dijkstra)是由荷蘭計(jì)算機(jī)科學(xué)家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是從一個頂點(diǎn)到其余各頂點(diǎn)的最短路徑算法。本文將用C++實(shí)現(xiàn)Dijkstra算法,需要的可以參考一下2022-07-07C/C++?Qt?數(shù)據(jù)庫與TableView實(shí)現(xiàn)多組件聯(lián)動
Qt?數(shù)據(jù)庫組件與TableView組件實(shí)現(xiàn)聯(lián)動效果,本文通過案例給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-12-12C語言中static的作用及C語言中使用靜態(tài)函數(shù)有何好處
在C語言中,static的作用有三條:一是隱藏功能,二是保持持久性功能,三是默認(rèn)初始化為0。本文重點(diǎn)給大家介紹C語言中static的作用及c語言中使用靜態(tài)函數(shù)有何好處,對本文感興趣的朋友一起看看吧2015-11-11詳解C語言隨機(jī)數(shù)設(shè)置的三種方式(保姆級教程)
本篇文章將為大家介紹在C語言中設(shè)置隨機(jī)數(shù)的三大方法的使用,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C語言有一定的幫助,需要的可以參考一下2022-11-11C++實(shí)現(xiàn)中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-04-04