網站首頁 編程語言 正文
一、結構體
結構體是不同類型變量的集合體
1.結構體的聲明
struct Book { char name[20];//名字 int Price;//價格 char Writer[5];//作者 char Time[20];//日期 }; //注意分號不能丟
struct為結構體關鍵字,Book為結構體標簽,中間不同類型的變量為結構體的成員。上述現在只是定義了一個結構體類型struct Book。
局部結構體變量
int main() { struct Book B1; // B1為局部結構體變量 return 0; }
全局結構體變量
struct Book { char name[20]; int Price; char Writer[5]; char Time[20]; }B3,B4,B5; //在結構體類型后可連續定義多個全局結構體變量 struct Book B2; //B2為全局結構體變量 int main() { return 0; }
2.特殊聲明
不完全聲明
//匿名結構體類型--沒有結構體標簽 struct { int a; char b; float c; }x; //這樣的結構體類型必須緊跟著定義結構體變量 //后面不能定義變量
不完全聲明類型只能在定義使用一次,并且在vs中:
struct { int a; char b; float c; }x; struct { int a; char b; float c; }* ps; int main() { ps=&x; //編譯器默認兩者類型不兼容 //且是錯誤寫法 return 0; }
因此不完全聲明很少使用,不推薦。?
3.結構體的自引用
這里可以用鏈表的實現來理解:
struct Node { int data; struct Node* next; };
這樣就實現了自己類型的對象找自己類型對象的方法,這就是結構體的自引用。?
4.結構體變量的初始化
以上面struct Book為例:
struct Book { char name[20]; int Price; char Writer[5]; char Time[20]; }; int main() { struct Book B1={"三腳貓",50,“阿里”,“20081001”}; //初始化要用大括號 return 0; }
嵌套結構體的初始化:
struct Data { int a; char b[6]; }; struct Book { struct Data D; char name[20]; int Price; char Writer[5]; char Time[20]; }; int main() { struct Book B1={{4,"haha"},"三腳貓",50,"阿里","20081001"}; //大括號里加大括號 return 0; }
5.結構體內存對齊?
計算結構體在內存中的大小
方法:
1. 第一個成員為起始,設從下標為0的地址開始向后存儲。
2. 其他成員變量要對齊到對齊數的整數倍的地址處。 對齊數 = 編譯器默認的一個對齊數與 該成員大小的較小值。 VS中默認的值為8
3. 結構體總大小為所有成員對齊數中最大對齊數的整數倍。
4. 如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍。
舉例說明:
#include <stdio.h> struct S1 { char c1; int i; char c2; }; struct S2 { char c1; char c2; int i; }; int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0; }
分析:
嵌套結構體
#include <stdio.h> struct S1 { char c1; int i; char c2; }; struct S2 { char c1; char c2; struct S1 s1; int i; }; int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0; }
分析:
內存對齊的存在,在平臺和性能兩方面,可以使訪問空間更加高效,用空間換取時間。
讓占用空間小的成員盡量集中在一起。
6.修改默認對齊數
#pragma pack(1) //修改默認對齊數為1 //一般修改的對齊數為2^n
舉例說明:
#include <stdio.h> #pragma pack(1) //修改為1相當于取消了對齊,沒有優化,在實際應用中很少用 struct S1 { char c1; int i; char c2; }; int main() { printf("%d\n", sizeof(struct S1)); // 6 return 0; }
當默認對齊數被修改后,每個類型的對齊數都變為1,整體的最大對齊數也為1(相當于沒有對齊),整體大小是1的倍數,則1+4+1=6。
7.結構體傳參
當一個函數涉及到結構體時,最好用傳址調用:
struct S { int data[1000]; int num; }; struct S s = {{1,2,3,4}, 1000}; //結構體傳參 void print1(struct S s) { printf("%d\n", s.num); } //結構體地址傳參 void print2(struct S* ps) { printf("%d\n", ps->num); } int main() { print1(s); //傳結構體 print2(&s); //傳地址 return 0; }
傳址調用原因:
1.函數傳參的時候,參數是需要壓棧,會有時間和空間上的系統開銷。
2.如果傳遞一個結構體對象的時候,結構體過大,參數壓棧的的系統開銷比較大,所以會導致性能的下降。
二、位段
位段的聲明和結構是類似的,有兩個不同:
1.位段的成員必須是整型。
2.位段的成員名后邊有一個冒號和一個數字。
舉例:
struct S { int _a:2; int _b:5; int _c:20; int _d:25; };
此時S就是一個位段類型
他的大小為8
printf("%d\n", sizeof(struct S));
分析:
下面我們來分析位段在內存中的存儲:
注:若初始化的值大于給其指定的空間,則先會發生截斷(斷左取右),再進行存儲
位段是根據實際需求來進行開辟空間,目的是為了節省空間提高效率。
跨平臺問題:
1. int 位段被當成有符號數還是無符號數是不確定的。
2. 位段中最大位的數目不能確定。(16位機器最大16,32位機器最大32,寫成27,在16位機 器會出問題。
3. 位段中的成員在內存中從左向右分配,還是從右向左分配標準尚未定義。(取決于編譯器)
4. 當一個結構包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是 舍棄剩余的位還是利用,這是不確定的。
三、枚舉
就是把可能的取值一一列舉
枚舉類型的定義:
例子:
enum Day //星期 { Mon, Tues, Wed, Thur, Fri, Sat, Sun };
enum Day就是一個枚舉類型,{}中的內容是枚舉類型的可能取值,也叫枚舉常量。
枚舉常量是有值的,默認從0開始,依次遞增。
int main() { enum Day d=Mon; //定義一個變量,賦予{}內可能的取值。 return 0; }
在定義的時候也可以賦初值,后面的常量依次遞增一
枚舉的優點?
1. 增加代碼的可讀性和可維護性
2. 和#define定義的標識符比較枚舉有類型檢查,更加嚴謹。
3. 防止了命名污染(封裝)
4. 便于調試
5. 使用方便,一次可以定義多個常量
注:最好用枚舉常量給枚舉變量賦值,才不會出現類型上的差異。
舉例:
當用cpp來運行程序時會報錯,因為cpp對代碼的格式會更加嚴格
而c就可以運行過去
養成良好的代碼風格,做到認真嚴謹。
四、聯合
聯合也是一種特殊的自定義類型
1.聯合類型的定義
//聯合類型的聲明 union Un { char c; int i; }; //聯合變量的定義 union Un un; //計算連個變量的大小 printf("%d\n", sizeof(un));
2.聯合的特點?
聯合的成員是共用同一塊內存空間的,這樣一個聯合變量的大小,至少是最大成員的大小。
union Un { int i; char c; }; union Un un; int main() { printf("%d\n", &(un.i)); printf("%d\n", &(un.c)); return 0; }
共用一塊空間,起始地址相同。
使用案例:
union Un { int i; char c; }; union Un un; int main() { //printf("%d\n", &(un.i)); //printf("%d\n", &(un.c)); un.i = 0x11223344; un.c = 0x55; printf("%x\n", un.i); return 0; }
分析:
3.聯合大小的計算?
聯合的大小至少是最大成員的大小。
當最大成員大小不是最大對齊數的整數倍的時候,就要對齊到最大對齊數的整數倍。
舉例:
union Un1 { char c[5]; int i; }; union Un2 { short c[7]; int i; }; //下面輸出的結果是什么? int main() { printf("%d\n", sizeof(union Un1)); printf("%d\n", sizeof(union Un2)); return 0; }
分析:
原文鏈接:https://blog.csdn.net/weixin_53316121/article/details/122730442
相關推薦
- 2022-06-16 C#使用符號表實現查找算法_C#教程
- 2022-07-12 k8s 之 service ip
- 2023-03-20 C#如何刪除指定文件或文件夾_C#教程
- 2022-06-19 教你用vbs實現微信自動發送消息功能_vbs
- 2022-05-17 python的列表生成式,生成器和generator對象你了解嗎_python
- 2023-10-31 SpringBoot手動獲取實例
- 2022-11-30 C語言中順序棧和鏈棧的定義和使用詳解_C 語言
- 2022-07-01 Go官方限流器的用法詳解_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支