C語言編程C++自定義個(gè)性化類型
自定義類型
結(jié)構(gòu)體
結(jié)構(gòu)是一些值的集合,這些值稱為成員變量。結(jié)構(gòu)的每個(gè)成員可以是不同類型的變量
聲明一個(gè)結(jié)構(gòu)體類型
//聲明一個(gè)學(xué)生類型,是想通過學(xué)生類型來創(chuàng)建學(xué)生變量(對(duì)象) //描述學(xué)生就得有屬性啥的。名字,電話,性別,年齡 struct Stu { char name[20];//名字 char tele[12];//電話 char sex[10];//性別 int age;//年齡 }; struct Stu s3;//創(chuàng)建全局結(jié)構(gòu)體變量 int main() { struct Stu s1; struct Stu s2;//創(chuàng)建結(jié)構(gòu)體變量 return 0; }
特殊聲明
在聲明結(jié)構(gòu)的時(shí)候,可以不完全的聲明。
沒有結(jié)構(gòu)體標(biāo)簽
匿名結(jié)構(gòu)體類型
要清楚一點(diǎn)匿名結(jié)構(gòu)體是個(gè)類型不占用空間的,就好像int一樣,他們沒有創(chuàng)建一個(gè)變量是不會(huì)開辟空間的,所以類型不占用空間就沒有銷毀不銷毀這一說,只有有了空間才會(huì)有銷毀不銷毀這一說,類型就好像圖紙,變量才是真正要蓋的房子
struct { char name[20];//名字 char tele[12];//電話 char sex[10];//性別 int age;//年齡 }stu;//直接接結(jié)構(gòu)體變量,匿名的時(shí)候后面就把變量給創(chuàng)建好,不然之后也用不到這個(gè)結(jié)構(gòu)名,因?yàn)闆]有結(jié)構(gòu)體名字怎么創(chuàng)建變量呢
匿名結(jié)構(gòu)體指針類型
struct { char name[20];//名字 char tele[12];//電話 char sex[10];//性別 int age;//年齡 }* pstu;//這時(shí)pstu就變成匿名結(jié)構(gòu)體指針了
結(jié)構(gòu)體自引用
在結(jié)構(gòu)中包含一個(gè)類型為該結(jié)構(gòu)本身的成員是否可以呢?
所以節(jié)點(diǎn)(Node)就出來了
一塊表示數(shù)據(jù)一塊表示地址
struct Node { int data; //數(shù)據(jù)域 struct Node* next; //指針域 };
這就是結(jié)構(gòu)體自引用 自己類型里的變量找到同類型的另外一個(gè)對(duì)象
注意
所以對(duì)于結(jié)構(gòu)體的自引用是不能省略自己的結(jié)構(gòu)體標(biāo)簽,下面就是解決方案
typedef struct Node { int data; //數(shù)據(jù)域 struct Node* next; //指針域 }Node;
結(jié)構(gòu)體變量的定義和初始化
struct Stu { char name[20];//名字 char tele[12];//電話 char sex[10];//性別 int age;//年齡 }; struct Stu s3;//創(chuàng)建全局結(jié)構(gòu)體變量 int main() { struct Stu s1 = {"zhuzhongyuan","13151732661","nan",22};//(定義)創(chuàng)建結(jié)構(gòu)體變量s1并初始化 printf("%s %s %s %d",s1.name,s1.tele,s1.sex,s1.age); return 0; }
結(jié)構(gòu)體內(nèi)存對(duì)齊
現(xiàn)在我們深入討論一個(gè)問題:計(jì)算結(jié)構(gòu)體的大小。
這也是一個(gè)特別熱門的考點(diǎn):結(jié)構(gòu)體內(nèi)存對(duì)齊
#include<stdio.h> //內(nèi)存對(duì)齊 //結(jié)構(gòu)體內(nèi)存對(duì)齊 struct S2 { int a; char b; char c; }; struct S1 { char b; int a; char c; }; int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0; }
結(jié)構(gòu)體內(nèi)存對(duì)齊的規(guī)則
- 結(jié)構(gòu)體的第一個(gè)成員永遠(yuǎn)放在結(jié)構(gòu)體起始位置偏移量為0的位置
- 結(jié)構(gòu)體成員從第二成員開始,總是放在一個(gè)對(duì)齊數(shù)的整數(shù)倍處
- 對(duì)齊數(shù)是什么呢是編譯器默認(rèn)的對(duì)齊數(shù)和變量自身大小的較小值注意一下 linux沒有默認(rèn)對(duì)齊數(shù)vs下默認(rèn)對(duì)齊數(shù)是8
- 結(jié)構(gòu)體的總大小必須是各個(gè)成員的對(duì)齊數(shù)中最大那個(gè)對(duì)齊數(shù)的整數(shù)倍
- 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍
幾個(gè)練習(xí)
為什么存在內(nèi)存對(duì)齊
1.平臺(tái)原因(移植原因)
不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù),某些平臺(tái)只能在某些地址某些特定類型的數(shù)據(jù),否則拋出硬件異常
2.性能原因
數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊,原因在于,為了訪問未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問,而對(duì)齊的訪問僅需要一次訪問
總體來說
結(jié)構(gòu)體內(nèi)存對(duì)齊就是拿空間換取時(shí)間的做法,形象的說就是浪費(fèi)了內(nèi)存,換來了方便
解決
那在設(shè)計(jì)結(jié)構(gòu)體的時(shí)候,我們既要滿足對(duì)齊,又要節(jié)省空間,如何做到:
讓占用空間小的成員盡量集中在一起。
修改默認(rèn)對(duì)齊數(shù)
vs默認(rèn)對(duì)齊數(shù)是8
我們可以通過#pragma pack()來修改默認(rèn)對(duì)齊數(shù)
默認(rèn)設(shè)置對(duì)齊數(shù)是2的幾次方
offsetof宏的實(shí)現(xiàn)
計(jì)算結(jié)構(gòu)體中某變量相對(duì)于首地址的偏移
offsetof原格式
結(jié)構(gòu)體傳參
值傳遞
址傳遞
如何選擇
1.函數(shù)傳參的時(shí)候,參數(shù)是需要壓棧,會(huì)有時(shí)間和空間上的系統(tǒng)開銷。
2.如果傳遞一個(gè)結(jié)構(gòu)體對(duì)象的時(shí)候,結(jié)構(gòu)體過大,參數(shù)壓棧的的系統(tǒng)開銷比較大,所以會(huì)導(dǎo)致性能的下降。
結(jié)論: 結(jié)構(gòu)體傳參的時(shí)候,要傳結(jié)構(gòu)體的地址。
位段
什么是位段
位段的聲明和結(jié)構(gòu)體類似,有兩個(gè)不同
1.位段的成員必須是int,unsiged int 或 signed int
2.位段的成員后面有一個(gè)冒號(hào)和一個(gè)數(shù)字
位段的內(nèi)存分配 位段的成員可以是int, unsigned int,signed int,或者是char(屬于整形家族)類型位段的空間上是按照需要以4個(gè)字節(jié)(int)或者1個(gè)字節(jié)(char)的方式來開辟的位段涉及很多不確定因素,位段是不跨平臺(tái)的,注重可移植的程序應(yīng)該避免使用位段
位段的跨平臺(tái)問題 int 位段被當(dāng)成有符號(hào)數(shù)還是無符號(hào)數(shù)是不確定的。位段中最大位的數(shù)目不能確定。(16位機(jī)器最大16,32位機(jī)器最大32,寫成27,在16位機(jī)器會(huì)出問題。位段中的成員在內(nèi)存中從左向右分配,還是從右向左分配標(biāo)準(zhǔn)尚未定義。當(dāng)一個(gè)結(jié)構(gòu)包含兩個(gè)位段,第二個(gè)位段成員比較大,無法容納于第一個(gè)位段剩余的位時(shí),是舍棄剩余的位還是利用,這個(gè)也是不確定的。 總結(jié):
跟結(jié)構(gòu)相比,位段可以達(dá)到同樣的效果,可以很好的節(jié)省空間,但是有跨平臺(tái)的問題存在。
位段的應(yīng)用
枚舉
如果我們沒有對(duì)枚舉常量進(jìn)行初始化的話,他們是默認(rèn)加一的
我們常量分為4種
1.字面常量
2.const修飾的常變量
3.#號(hào)定義的標(biāo)識(shí)符常量
4.枚舉常量
這里我們就講枚舉常量
枚舉常量是不可以改的,只能初始化
那枚舉怎么用呢
枚舉的優(yōu)點(diǎn)
我們可以使用 #define 定義常量,為什么非要使用枚舉? 枚舉的優(yōu)點(diǎn):
增加代碼的可讀性和可維護(hù)性和#define定義的標(biāo)識(shí)符比較枚舉有類型檢查,更加嚴(yán)謹(jǐn)。防止了命名污染(封裝)便于調(diào)試
而define是不可以的,因?yàn)閐efine是完完全全替換的,在代碼中看到GREEN什么的直接替換為1,代碼中就沒有GREEN的概念了,完完全全的替換
使用方便,一次可以定義多個(gè)常量 簡(jiǎn)易計(jì)算器
#include<stdio.h> enum Option { exit, add, sub, mul, div }; void menu() { printf("*********************\n"); printf("****1.add 2.sub****\n"); printf("****3.mul 4.div****\n"); printf("**** 0.exit ****\n"); printf("*********************\n"); } int main() { int input = 0; int a = 0; int b = 0; int c = 0; do { menu(); printf("請(qǐng)選擇:>"); scanf("%d",&input); printf("請(qǐng)輸入兩個(gè)操作數(shù):>"); scanf("%d%d", &a, &b); switch (input) { case add: c = a + b; printf("%d\n", c); break; case sub: c = a - b; printf("%d\n", c); break; case mul: c = a * b; printf("%d\n", c); break; case div: if (b == 0) { printf("分子不能為0\n"); break; } else { c = a / b; printf("%d\n", c); break; } default: break; } } while (input); return 0; }
聯(lián)合(共用體)
聯(lián)合類型的定義
聯(lián)合也是一種特殊的自定義類型 這種類型定義的變量也包含一系列的成員,特征是這些成員公用同一塊空間(所以
聯(lián)合也叫共用體)。
聯(lián)合類型的聲明
聯(lián)合的特點(diǎn)
聯(lián)合的成員是共用同一塊內(nèi)存空間的,這樣一個(gè)聯(lián)合變量的大小,至少是最大成員的大?。ㄒ?yàn)槁?lián)合至少得有能力保存最大的那個(gè)成員)
判斷當(dāng)前機(jī)器的大小端存儲(chǔ)【】
之前學(xué)過一個(gè)方法
#include<stdio.h> int main() { int a = 1; //0x 00 00 00 01 //低 -------------> 高 //01 00 00 00 小端存儲(chǔ) //00 00 00 01 大端存儲(chǔ) //想辦法拿到a的第一個(gè)字節(jié) char* pc = (char*)&a; if (*pc == 1) { printf("小端存儲(chǔ)"); } else { printf("大端存儲(chǔ)"); } return 0; }
現(xiàn)在學(xué)到共用體正好利用他的特殊情況
#include<stdio.h> union Un { char c; int i; }; int main() { union Un u = { 0 }; u.i = 1; if (u.c == 1) { printf("小端存儲(chǔ)"); } else { printf("大端存儲(chǔ)"); } return 0; }
聯(lián)合大小的計(jì)算
聯(lián)合的大小至少是最大成員的大小。
當(dāng)最大成員大小不是最大對(duì)齊數(shù)的整數(shù)倍的時(shí)候,就要對(duì)齊到最大對(duì)齊數(shù)的整數(shù)倍。
以上就是C語言編程C++自定義個(gè)性化類型的詳細(xì)內(nèi)容,更多關(guān)于C++自定義類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于C++11的統(tǒng)一初始化語法示例詳解
C++之前的初始化語法很亂,有四種初始化方式,而且每種之前甚至不能相互轉(zhuǎn)換,但從C++11出現(xiàn)后就好了,所以這篇文章主要給大家介紹了關(guān)于C++11的統(tǒng)一初始化語法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。2017-10-10簡(jiǎn)單聊聊C++中線程的原理與實(shí)現(xiàn)
C++11?引入了多線程支持,提供了一套基本的線程庫(kù),包括線程、互斥量(mutex)、條件變量(condition_variable)等。這些組件可以幫助你在?C++?程序中實(shí)現(xiàn)并發(fā)和多線程編程,本文就來和大家簡(jiǎn)單聊聊吧2023-03-03C語言結(jié)構(gòu)體數(shù)組常用的三種賦值方法(包含字符串)
C語言只有在定義字符數(shù)組的時(shí)候才能用“=”來初始化變量,其它情況下是不能直接用“=”來為字符數(shù)組賦值的,下面這篇文章主要給大家介紹了關(guān)于C語言結(jié)構(gòu)體數(shù)組常用的三種賦值方法,需要的朋友可以參考下2022-06-06用標(biāo)準(zhǔn)c++實(shí)現(xiàn)string與各種類型之間的轉(zhuǎn)換
這個(gè)類在頭文件中定義, < sstream>庫(kù)定義了三種類:istringstream、ostringstream和stringstream,分別用來進(jìn)行流的輸入、輸出和輸入輸出操作。另外,每個(gè)類都有一個(gè)對(duì)應(yīng)的寬字符集版本2013-09-09