C語言學習之結構體

? ? ?在C語言中,我們已經學了好幾種類型的數據。比如整型int、char、short等,浮點型double、float等。但是這些都是基本數據類型,而這些數據類型應用在實際編程里顯然是不夠用的。比如我們沒有辦法用一旦數據類型來定義一個”人“的屬性。因此這里我們需要一個框,將不同的數據類型放在一起,這就是結構體,接下來我們將深入學習結構體的知識。

結構體

結構體的創建與初始化

? ? ? ? 結構體是一些值的集合,這些值被稱之為成員變量。結構的每個成員都是不同類型的變量。

? ? ? ? 語法結構:

struct name//名字自定義
{member-list;//一個或者多個成員變量
}variable-list//可以省略。是結構體變量列表

舉例說明

struct person
{char name[20];int age;float height;
};
int main()
{struct person p1 = {"詩華",18,1.72};return 0;
}

結構體的特殊聲明

? ? ? ? 聲明結構體的時候可以不完全聲明。

? ? ? ? 但是匿名結構體的聲明其后必須創建變量

struct//匿名結構體類型
{char name[20];int age;float height;
}s1,s2;

????????匿名結構體類型只能用一次。

? ? ? ? 但是切記這種方法不行

拓展:數據結構簡單科普

????????鏈表是一種數據結構。數據結構是描述數據在內存當中的存儲結構,對數據的操作就是對數據結構的操作。

? ? ? ? 大體上數據結構分為以下幾種

結構的自引用

????????在結構體中包含一個類型為該結構本身的成員是否可以呢?

上圖報錯的原因:結構體內不能包含同類型的自己。?

如果想正確表達,需要這樣

struct Node
{int data;struct Node *next;
};int main()
{printf("%zd\n",sizeof(struct Node));/*struct person p1 = {"詩華",18,1.72};*/return 0;
}

結果為:?

而在上圖中,int data為數據域,struct Node * next為指針域。

? ? ? ? 也可以簡化為:

typedef struct Node
{int data;struct Node *next;
}Node;

之后如果使用結構體定義變量可以直接寫為

Node n;

但是這么些是絕對錯誤的

typedef struct 
{int data;Node *next;
}Node;

結構體內存對齊

? ? ? ? 我們學會結構體的基本使用后,那么問題來了,結構體的大小是怎么計算的呢?我們舉例分析。

#include<stdio.h>
struct s1
{char c1;//1char c2;//1int n;//4
};
struct s2
{char c1;//1int n;//4char c2;//1
};
struct s3
{double d1;//8int n;//1char c1;//4
};
struct s4
{double d1;//8struct s3 S;//16char c2;//1
};
int main()
{printf("%zd\n",sizeof(struct s1));printf("%zd\n", sizeof(struct s2));printf("%zd\n",sizeof(struct s3));printf("%zd\n",sizeof(struct s4));return 0;
}

結果為:

????????

? ? ? ? 為什么是這樣呢?

? ? ? ? 結構體成員在存儲的時候有內存對齊的現象。

? ? ? ? 這里介紹一個新概念:offsetof——一個宏,可以計算出一個結構體成員相較于結構體起始位置的偏移量。(其實之前博主的博客預處理那節講解過:C語言學習之預處理指令-CSDN博客)

? ? ? ? 內存對齊的規則

1.結構體的第一個成員對齊到和結構體變量起始位置偏移量為0的地址處。

2.其他成員變量要對齊到某個數字(對齊數)的整數被的地址處

對齊數=編譯器默認的一個對齊數與該成員變量大小的較小值。

VS中默認的值為8

Linux中gcc編譯器沒有默認對齊數,對齊數就是成員變量自身的大小

3.結構體總大小為最大對齊數(結構體中每個成員變量都有一個對齊數,所有對齊數中最大值)的整數倍

4.如果嵌套了結構體的情況下,嵌套的結構體成員對齊到自己成員中最大對其數的整數倍,結構體的整體大小就是所有最大對其數(含嵌套結構體中成員的對齊數)的整數倍。

????????

?

為什么會存在內存對齊?

1.不是所有的硬件平臺都能訪問任意地址的任意數據;某些硬件平臺只能在某些地址處去某些特定類型的數據。

2.數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要做兩次內存訪問;而對齊的內存訪問僅僅需要一次訪問。

總結來說:結構體的內存對齊是拿空間換取時間的做法

那在設計結構體的時候,我們既要滿足對齊,又要節省空間如何做到呢“

讓占用空間小的成員盡量集中在一起。

struct A
{char c1;char c2;int n;
};
struct B
{char c1;int n;char c2;
};
int main()
{printf("%zd\n",sizeof(struct A));printf("%zd\n",sizeof(struct B));return 0;
}

修改默認對齊數

? ? ? ? #pragma這個預處理指令可以改變編譯器默認對齊數量。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#pragma pack(1)//設置結構體默認對齊數為1
struct S 
{char c1;int n;char c2;
};
#pragma	pack()//恢復默認對齊數int main()
{printf("%d\n",sizeof(struct S));return 0;
}

結構體傳參

?????????

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{int data[1000];int num;
};
struct S s = { {1,2,3,4,5} ,1000 };
//結構體傳參
void print1(struct S s)
{printf("%d\n",s.num);
}
void print2(struct S *ps)
{printf("%p\n",ps->num);
}
int main()
{print1(s );print2(&s);return 0;
}

? ? ? ? 上面的print1和print 2哪個更好呢?答案是print2

原因:

函數傳參的時候,參數是需要壓棧的,會有時間和空間上系統的開銷。

如果傳遞一個結構體對象時,結構體體積過大,參數壓棧的系統開銷過大,會導致性能下降。

結論:結構體傳參的時候,要穿結構體的地址

結構體實現位段??

? ? ? ? 位段

? ? ? ??位段的聲明和結構必須要類似,有兩個不同。

1.位段的成員必須是int,unsigned int或者signed int 。在C99中位段成員類型也可以是其他類型

2.位段的成員名之后有一個冒號和一個數字

#include<stdio.h>
//結構體
struct A
{int a;int b;int c;int d;
};
//位段
struct B
{int _a:2;int _b : 3;int _c : 10;int _d : 5;
};
int main()
{printf("%zd\n", sizeof(struct A));printf("%zd\n", sizeof(struct B));return 0;
}

結構體和位段的大小分別為:?

????????

位段的空間是如何開辟的呢?

位段的內存分配

1.位段的成員可以是:int,unsigned int或者signed int或者char類型

2.位段的空間上按照需要以4個字節和1個字節的方式開辟

3.位段涉及很多不確定因素,位段是不跨平臺的,注重可移植程序的程序避免使用。

//位段
struct B
{int _a:2;int _b : 3;int _c : 10;int _d : 30;
};
int main()
{/*printf("%zd\n", sizeof(struct A));*/printf("%zd\n", sizeof(struct B));return 0;
}

1.int位段被當成有符號還是無符號不確定

2.位段最大位的數目不確定(16位機器最大16,32位機器最大32.寫成27的話16 位機器會出問題)

3.位段成員在內存中從左向右分配還是右向左分配是不確定的

4.當一個結構體包含兩個位段的時候,第二個位段成員比較大,無法榮達第一個剩余的位時是舍棄剩余位置還是保留不確定

總結:與結構相比,位段可以達到同樣的效果,更加節省空間不過會有跨平臺的問題。

位段的應用

在網絡協議的IP數據報中,用位段可以更節省空間的達到想要的效果,對網絡暢通很有幫助。

?位段使用的注意事項

? ? ? ??位段的幾個成員共同用一個字節,這樣有i協成員起始位置并不是某個字節起始位置,那么這些位置只是沒有地址的。內存中每個字節分配一個地址,一個字節內部的比特位是沒有地址的。

? ? ? ? 所以不能對位段的成員使用&*操作符,這樣就不能直接使用scanf直接給位段的成員輸入值。只能先輸入放在一個變量里然后賦值給位段的成員

struct B
{int _a:2;int _b : 5;int _c : 10;int _d : 30;
};
int main()
{struct B s = {0};scanf("%d",&sa.b);//這是錯誤的//正確示范int b = 0;scanf("%d",b);sa._b = b;return 0;
}

感謝看到這里的讀者朋友,求一個贊謝謝。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/77500.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77500.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77500.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

架構-計算機系統基礎

計算機系統基礎 一、計算機系統組成 &#xff08;一&#xff09;計算機系統層次結構 硬件組成 主機&#xff1a;包含CPU&#xff08;運算器控制器&#xff09;、主存儲器&#xff08;內存&#xff09;。外設&#xff1a;輸入設備、輸出設備、輔助存儲器&#xff08;外存&…

【計算機網絡性能優化】從基礎理論到實戰調優

目錄 前言技術背景與價值當前技術痛點解決方案概述目標讀者說明 一、技術原理剖析核心概念圖解核心作用講解關鍵技術模塊說明技術選型對比 二、實戰演示環境配置要求核心代碼實現案例1&#xff1a;iPerf3帶寬測試案例2&#xff1a;TCP窗口優化案例3&#xff1a;QoS流量整形 運行…

Python 自動化辦公:Excel 數據處理的“秘密武器”

引言 在日常的 IT 辦公場景里&#xff0c;Excel 是數據處理與分析的 “常勝將軍”。無論是財務人員整理賬目、銷售團隊統計業績&#xff0c;還是運營人員分析用戶數據&#xff0c;Excel 都發揮著關鍵作用。但面對海量數據&#xff0c;手動操作 Excel 不僅效率低下&#xff0c;還…

緩存集群技術深度解析:從原理到實戰

緩存集群技術深度解析&#xff1a;從原理到實戰 一、緩存集群核心定位與架構選型 1. 集群模式核心價值 緩存集群通過數據分片、高可用保障、水平擴展解決單節點瓶頸&#xff0c;核心能力包括&#xff1a; 數據分片&#xff1a;將數據分散到多個節點&#xff0c;突破單節點內…

CSDN編輯文章時如何自動生成目錄

如何自動生成目錄 前置條件1. 插入目錄標識符2. 編寫標題層級 前置條件 需要使用markdown編輯&#xff0c;并且只有按照markdown語法編寫不同的標題級別&#xff0c;才能使用這個方法自動生成對應的目錄。 1. 插入目錄標識符 在文章的頂部添加以下代碼&#xff1a; [TOC](文…

產品經理對于電商接口的梳理||電商接口文檔梳理與接入

接口梳理7個注意點總結 ①注意要測試環境和生產環境。生產上線時候要提醒研發換到生產環境調用。 ②注意必輸字段和選輸字段&#xff0c;要傳入字段的含義和校驗。枚舉值不清楚含義的要詢問對方含義&#xff0c;比如說單據類型字段枚舉值是B2C發貨單&#xff0c;BBC發貨單&am…

更快的圖像局部修改與可控生成:Flex.2-preview

Flex.2-preview 文本生成圖像擴散模型介紹 一、模型簡介 Flex.2-preview 是一種 開源的 80 億參數文本生成圖像擴散模型&#xff0c;具備通用控制和修復支持功能&#xff0c;是 Flex.1alpha 的下一代版本。該模型由社區開發并為社區服務&#xff0c;采用 Apache 2.0 許可證&a…

【Castle-X機器人】一、模塊安裝與調試:機器人底盤

持續更新。。。。。。。。。。。。。。。 【ROS機器人】模塊安裝 一、Castle-X機器人底盤1.1 結構概述1.2 驅動執行結構1.3 環境傳感器1.4 電氣系統1.5 Castle-x機器人底盤測試激光雷達傳感器測試及數據可視化超聲波傳感器實時數據獲取防跌落傳感器測試陀螺儀測試鍵盤控制測試…

條件、列表渲染.

#### v-for 1. 渲染列表 vue <template> <ul v-for"(item,index) in list" > <li>{{ item }}</li> </ul> </template> <script setup> import { ref } from vue; let list ref([蘋果, 香蕉, 橙子]) </script>…

node20的安裝和vue的入門準備

一、node20的安裝 直接下載路徑&#xff1a;https://nodejs.org/download/release/v20.11.0/node-v20.11.0-x64.msi 安裝&#xff0c;雙擊msi文件 點擊同意協議 更改下載路徑 什么也不用選&#xff0c;點擊next進行下一步 什么也不用選&#xff0c;點擊next進行下一步 點擊安…

從 Java 到 Kotlin:在現有項目中遷移的最佳實踐!

全文目錄&#xff1a; 開篇語 1. 為什么選擇 Kotlin&#xff1f;1.1 Kotlin 與 Java 的兼容性1.2 Kotlin 的優勢1.3 Kotlin 的挑戰 2. Kotlin 遷移最佳實踐2.1 漸進式遷移2.1.1 步驟一&#xff1a;將 Kotlin 集成到現有的構建工具中2.1.2 步驟二&#xff1a;逐步遷移2.1.3 步驟…

威雅利電子|業界領先的高隔離度用于5G基站的吸收式SPDT開關“NT1819“

業界領先的高隔離度 用于5G基站的吸收式SPDT開關"NT1819" 為了實現智能社會&#xff0c;已經啟動了5G服務。這樣&#xff0c;高速、低延遲、大容量的數據通信成為可能&#xff0c;也給我們的生活和工業發展帶來了巨大的變化。 在5G基站有很多天線&#xff0c;每個天…

Diamond軟件的使用--(6)訪問FPGA的專用SPI接口

1.什么是FPGA的專用SPI接口&#xff1f; 此處的SPI FLASH接口即為FPGA的專用SPI接口&#xff0c;上電時&#xff0c;FPGA從該FLASH讀出程序并運行。 2.訪問SPI PROM需要注意哪些地方&#xff1f; 1&#xff09;處于MASTER SPI MODE 2&#xff09;調用USRMCLK原語&#xff0c;…

Go 語言中的 `select` 語句詳解

select 是 Go 語言中處理通道(Channel)操作的一個強大控制結構&#xff0c;它允許 goroutine 同時等待多個通道操作。下面我將全面詳細地解釋 select 語句的各個方面。 基本語法 select 語句的基本語法如下&#xff1a; select { case <-ch1:// 如果從 ch1 成功接收數據&…

AI如何重塑CC防護行業?五大變革與實戰策略解析

一、CC防護行業的技術痛點與AI的破局方向 CC攻擊&#xff08;Challenge Collapsar&#xff09;作為一種以高頻合法請求消耗服務器資源的DDoS攻擊手段&#xff0c;傳統防護技術面臨三大核心挑戰&#xff1a; 規則依賴性強&#xff1a;基于IP封禁或請求頻率的靜態規則易被繞過&a…

GPT-4o最新圖像生成完全指南:10大應用場景與提示詞模板

引言 OpenAI于近期推出的全新GPT-4o圖像生成功能&#xff0c;代表了AI圖像創作領域的重大突破。作為一個原生多模態系統&#xff0c;GPT-4o將文本理解和圖像生成無縫整合&#xff0c;為創作者、教育工作者和專業人士提供了前所未有的視覺創作靈活性。本文將分享10個GPT-4o圖像…

Linux驅動開發2 - 內核定時器驅動

背景 所有驅動開發都是基于全志T507&#xff08;Android 10&#xff09;進行開發&#xff0c;用于記錄驅動開發過程。 簡介 定時器是比較常用的一個功能&#xff0c;用來執行周期性任務。一般不太精確的定時可以用系統提供的延時函數進行。如果需要進行較為精確的延時&#…

Dify 使用 excel 或者 csv 文件創建知識庫

Dify 使用 excel 或者 csv 文件創建知識庫 1. 創建知識庫2. 創建聊天助手3. 其他 1. 創建知識庫 創建知識庫&#xff0c;導入excel/csv文件&#xff0c; 文件內容&#xff0c; 單擊 “預覽塊”&#xff0c;可以確認會生成多個鍵值對的塊&#xff0c; 配置 Embedding 模型和檢索…

23種設計模式-行為型模式之迭代器模式(Java版本)

Java 迭代器模式&#xff08;Iterator Pattern&#xff09;詳解 &#x1f9e0; 什么是迭代器模式&#xff1f; 迭代器模式是一種行為型設計模式&#xff0c;它提供一種方法順序訪問一個聚合對象中的各個元素&#xff0c;而不暴露該對象的內部表示。 &#x1f3af; 使用場景 …

使用nodeJs的express+axios+cors做代理

使用nodeJs的expressaxioscors做代理 前端在請求后端時通常會遇到跨域cors問題&#xff0c;如果只在本地開發可以通過webpack或vite的proxy設置。但如果需要在線上或者其他地方繞過跨域&#xff0c;可以使用代理的方法。 1. 創建文件夾 并創建以下文件 package.json {"…