網站首頁 編程語言 正文
前言
初學C語言
我們先接觸的都是內置的類型
比如說int char short float double long等等
這一期就來聊一聊自定義類型的知識
結構體類型
首先我們要知道什么是結構體
結構體就是各種值集合
這些值被稱作結構體成員,這些成員可包括各種不同的類型
struct tag //這里的struct是結構體的關鍵字,tag是結構體標簽,也就是結構體的名稱 { number - list; //結構體成員列表 }veriable-list; //結構體的變量
結構體的聲明
如果結構體的標簽是student,我拿student來舉例子
結構體的完整聲明
struct Student { char name[20];//姓名 char sex;//性別 int age;//年齡 int num;//學號 }; //這里的分號不能丟
結構體的不完全聲明(匿名結構體類型)
struct { int a; char b; double c; }s; //這s不能省略
匿名結構體的特點就是沒有結構體標簽
但這樣寫用戶使用時只能使用一次,也就是說只能在結構體聲明時就定義變量
因為你找不到結構體標簽,就相當于找不到門牌號一樣,無法再對其定義一個變量
結構體變量的定義與初始化
結構體的定義大致分為三種情況
<1>結構體聲明的同時定義
struct Student { char name[20];//姓名 char sex[20];//性別 int age;//年齡 }s={"zhangsan","nan",20};
<2>結構體先聲明,再定義
#include<stdio.h> struct Student { char name[20];//姓名 char sex;//性別 int age;//年齡 int num;//學號 }; int main() { struct Student s = { "zhangsan",'w',20,111 }; return 0; }
<3>匿名結構體定義
struct { char name[20];//姓名 char sex[20];//性別 int age;//年齡 } s = { "zhangsan","nan",20};
注意:結構體初始化與數組相同,都必須整體進行賦值。
結構體的自引用
struct Node //初始話鏈表 { int a; struct Node next; };
結構體的自引用就是結構體再套用自己
學過數據結構的朋友應該知道這是初始化鏈表
不過這一個代碼有問題的
問題在于無法求出這個結構體的大小,不清楚這個結構體有多大,因為無法求出自引用的結構體有多大
所有自引用的結構體要用指針來訪問
struct Node //初始話鏈表 { int a; struct Node* next; };
故就可以通過指針來訪問每一個結點
結構體的訪問
當結構體定義且變量初始化完成后,就可以通過操作符來訪問變量中的成員
當然,這里給出了兩個操作符
分別是? .操作符和 -> 操作符
當使用結構體變量時,就用點操作符,當訪問結構體指針變量就用箭頭操作符
(1)通過結構體變量進行訪問:
printf("%s\n",s.name);
(2)通過結構體指針進行訪問:
printf("%s\n",ps->name);
結構體的傳參
函數的調用有時候需要傳一些參數
參數的類型可以是不同的類型,可以是數組,也可以是指針
同樣結構體的傳參也可通過傳結構體或者傳指針
傳結構體
#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; }
我們要知道函數傳參是形參就是實參的臨時拷貝
參數是要壓棧的(向系統申請空間),既然是臨時拷貝,就會再次再棧上開辟空間,當實參足夠大時,顯然會浪費一定的空間和時間
相比較與傳結構體,傳指針會更好?
結構體的內存對齊(強烈建議觀看)
在另外一篇文章詳細講過——C語言結構體中內存對齊的問題理解
位段
可能有人沒有聽過什么是位段
位段的結構類型跟結構體有些類似可以類似結構體去學習
也可以說
位段是結構體特殊的實現
位段的聲明
相較于結構體,位段的聲明有兩點不同
<1>規定位段的成員的必須是int,unsigned int ,signed int (但是寫成char類型也沒什么大的問題)
<2>位段的成員后面有一個冒號和一個數字
struct A //位段的聲明 { int _a : 2; int _b : 5; int _c : 10; int _d : 30; };
位段的內存管理
#include<stdio.h> struct A { int a : 2; int b : 5; int c : 10; int d : 30; }; int main() { printf("大小是%d字節", sizeof(struct A)); return 0; }
為什么位段的大小是八個字節呢?
成員內包含的數字代表的是這個成員需要利用的內存,單位是bit。
位段成員申請內存時都是以四個字節或者一個字節單位(當成員是char類型時)
int a : 2; //申請4個字節,也就是32個bit位,利用兩個還剩30個
int b : 5; //利用5個,還剩25個
int c : 10; //利用10個,還剩15個
int d : 30; //這里的十五不夠,所以再申請了4個字節
最終的結果就是八字節
但問題是,變量d利用的空間是留下的15個bit加上重新申請的空間呢
這個結果在不同的環境的結果是不同的,所以位段的跨平臺性比較差
位段使用的前提是你知道存儲的內存大概有多大
就比如說年齡
十個bit位0111111111,最大值就可以達到1023
就不需要再申請一次利用一個int類型的空間大小
這就達到了節省內存的作用,存在即合理
位段的應用?
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位段被當成有符號數還是無符號數是不確定的,有時候系統會自動轉化為無符號整形。
2.位段中最大位的數目不能確定。(因為在早期的16位機器int最大16,而32位機器int最大32)
3.位段中的成員在內存中從左向右分配,還是從右向左分配標準尚未定義。
意思當內存一個字節00000000,存入01010,可能會出現00001010或者01010000
4.當一個結構包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是 舍棄剩余的位還是利用,這是不確定的。
?枚舉類型
枚舉類型適用于可以一一列舉的類型
比如說星期、性別
枚舉類型的定義
enum Day //星期 { //枚舉的可能取值 Mon, Tues, Wed, Thir, Fri, Sta, Sun };
enum Sex //性別 { MALE,//0 FEMALE,//1 SECRET//2 };
枚舉類型是有初始值的
如果你沒賦予它初始值,就會默認從零開始,依次加一
枚舉類型賦予初始值
#include<stdio.h> enum Sex //性別 { MALE = 4, FEMALE=10, SECRET// }; main() { printf("%d %d %d", MALE,FEMALE,SECRET); return 0; }
可以看到,其實默認的值是可以改的
當某個成員被賦予某個值的時候,后續的成員就在此基礎上加一
枚舉類型的優點
1.相較于數字,枚舉增加代碼的可讀性和可維護性
2.和#define定義的標識符比較枚舉有類型檢查,更加嚴謹。
3.防止了命名污染(封裝)
4.便于調試
5.使用方便,一次可以定義多個常量
聯合體類型
聯合體類型也叫共用體
聯合體的定義
union Un { int a; char b; };
union是聯合體關鍵字,Un是聯合體的標簽
聯合體的特點
共用體,顧名思義,這里的共用就是公用內存
內存的也可被折疊
#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存放在同一塊內存空間上,修改c或者i都會影響到另一個成員。
?聯合體內存大小的計算
<1>聯合體內存大小是最大成員的大小
<2>最大成員的大小如果不是最大對齊數的整數倍,就會對齊到最大對齊數的整數倍
(聯合體也存在內存對齊)
#include<stdio.h> union Un1 { char c[5]; int i; }; //Un1成員最大成員大小5,最大對齊數是4,所以Un1的大小是8; union Un2 { char c[7]; int i; }; //Un2成員最大成員大小7,最大對齊數是4,所以Un2的大小是8; int main() { printf("%d\n", sizeof(union Un1)); printf("%d\n", sizeof(union Un2)); return 0; }
原文鏈接:https://z-ming.blog.csdn.net/article/details/122755619
相關推薦
- 2023-02-02 Go并發與鎖的兩種方式該如何提效詳解_Golang
- 2022-11-02 Python封裝解構以及丟棄變量_python
- 2022-05-21 Python中with上下文管理協議的作用及用法_python
- 2022-08-12 python使用pandas實現篩選功能方式_python
- 2022-06-25 Qt一個進程運行另一個進程的實現方法_C 語言
- 2022-03-17 Redis快速部署為Docker容器的實現方法_docker
- 2022-04-27 一篇文章了解正則表達式的替換技巧_正則表達式
- 2022-10-29 前端圖片上傳發現圖片倒置解決方案 圖片鏡像效果實現
- 最近更新
-
- 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同步修改后的遠程分支