【C語言】結構體內存對齊

目錄

引入結構體?

?結構的聲明

創建和初始化

?內部元素的使用;

特殊聲明:

結構體在內存中的對齊

練習:?



引入結構體?

? ? ? ? C語言有各種數據類型,我們已經對一些數據類型很熟悉:

  1. 整型(int)- 存儲整數值,包括有符號和無符號兩種類型。

  2. 浮點型(float、double、long double)- 存儲實數值,包括單精度(float)、雙精度(double)和長雙精度(long double)三種類型。

  3. 字符型(char)- 存儲單個字符,包括有符號和無符號兩種類型。

  4. 指針類型(pointer)- 存儲內存地址,可以指向其他數據類型。

? ? ? ? ?但是,僅僅有這些類型是無法描述一些對象的特征的,比如:一個人的多個信息,一個家庭的多個成員等等,那么這時候,就要用到結構體類型來描述一個比較復雜的對象。

? ? ? ? 結構體類型就像其他簡單數據類型(int,float,double)一樣,也是一種數據類型,但是它比較復雜,可以包含多個 簡單的數據類型, 這些被包含的數據類型可以是不同的類型。

?

?????????總之,結構體是為了描述復雜對象而引入的一種新的數據類型。

?結構的聲明

????????C語言中,結構體(struct)是一種自定義的數據類型,可以將不同的數據類型組合在一起形成一個?新的?數據類型。結構體的定義格式如下:

struct 結構體名稱
{數據類型1 成員變量1;數據類型2 成員變量2;...
} 創建的同類型結構體名稱;

?????????有了結構體類型,我們就可以描述復雜對象的特征。例如,要描述一個家庭的成員的信息,可以:

? ? ? ? 創建結構體類型Person——包含變量字符串型name, 整型age, 雙精度浮點型heignt;

? ? ? ? 創建結構體類型Family——包含結構體類型Person, 字符串型location;

?代碼如下:

?//聲明Person結構體類型struct Person {char name[20];int age;double height;
};//聲明Family結構體類型struct Family
{struct Person;char location[10];
}Family_of_my;?

從上述代碼可以得出:

????????結構體名稱 根據具體的實際意義來決定。

????????成員變量可以有多個,每個成員變量的數據類型可以是任意數據類型,包括簡單數據類型和復雜數據類型。也就是說,一個結構體內部可以再嵌套包含一個結構體類型。

?

? ? ? ? 總結,結構體內部的數據類型多樣,可以是簡單類型,也可以是復雜類型。

?

創建和初始化

? ? ? ? 結構體的初始化可以按照不同方式進行:

? ? ? ? 1.按照結構體內部元素順序

? ? ? ? 2.按照指定順序

#include <stdio.h>
struct Stu
{char name[20];//名字int age;//年齡char sex[5];//性別char id[20];//學號};int main()
{//按照結構體成員的順序初始化struct Stu s = { "張三", 20, "男", "20230818001" };printf("name: %s\n", s.name);printf("age : %d\n", s.age);printf("sex : %s\n", s.sex);printf("id : %s\n", s.id);//按照指定的順序初始化struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "?printf("name: %s\n", s2.name);printf("age : %d\n", s2.age);printf("sex : %s\n", s2.sex);printf("id : %s\n", s2.id);return 0;}

? ? ? ? 總結,?初始化可以按照正常順序,還可按照指定順序。

?內部元素的使用;

????????要用到結構體操作符。?

?
?
#include <stdio.h>
struct Stu
{char name[20];//名字int age;//年齡char sex[5];//性別char id[20];//學號};int main()
{//按照結構體成員的順序初始化struct Stu s = { "張三", 20, "男", "20230818001" };printf("name: %s\n", s.name);printf("age : %d\n", s.age);printf("sex : %s\n", s.sex);printf("id : %s\n", s.id);//按照指定的順序初始化struct Stu* s2 = &s;printf("name: %s\n", s2->name);printf("age : %d\n", s2->age);printf("sex : %s\n", s2->sex);printf("id : %s\n", s2->id);return 0;}??

?

? ? ? ? ?總結,要使用結構體內部元素,要用到結構體操作符:

.? 和 ->

用例:

結構體.成員名

結構體指針->成員名

特殊聲明:

????????在聲明結構的時候,可以不完全的聲明。也就是,可以省略結構體的標簽。

例如:

//匿名結構體類型
struct
{
int a;
char b;
float c;
}x;struct
{
int a;
char b;
float c;
}a[20], *p;

? ? ? ? 但是,這兩個匿名的類型完全一致的結構體是同一個結構體類型嗎?

也就是說:

p = &x;

????????這段代碼合法嗎?

? ? ? ? 經過測試,編譯器會把上面的兩個聲明當成完全不同的兩個類型,所以是?法的。
匿名的結構體類型,如果沒有對結構體類型重命名的話,基本上只能使??次。
?

?

結構體在內存中的對齊

? ? ? ? 現在,我們已經對結構體有了一個基本的認識,那么,結構體的大小是如何計算的呢?


?

? ? ? ? 我們先看一個實例:

計算下列兩個結構體的大小:


//練習1
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));//練習2
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));

? ? ? ? 我們可以先猜測:

????????既然兩個結構體內部的變量類型和數目完全一致,那么我們有理由猜測兩個結構體大小相同,但是,實際情況并不是這樣:

?

? ? ? ? 其實,結構體在內存中的存儲有一套自己的規則:

?首先,引入一個概念:

????????對齊數

????????對齊數=編譯器默認的?個對齊數? ?和 該成員變量長度的較小值

????????默認對齊數 :

VS 中默認的值為 8?


Linux中gcc沒有默認對?數,對?數就是成員??的??

結構體的基本對齊方法是:

????????1.結構體的第?個成員對?到和結構體變量起始位置偏移量為0的地址處
????????2.其他成員變量要對齊到對齊數的整數倍的地址處

結構體大小的計算:


????????1.結構體總??為最?對?數(結構體中每個成員變量都有?個對?數,所有對?數中最?的)的整數倍。


????????2.如果嵌套了結構體的情況,嵌套的結構體成員對?到??的成員中最?對?數的整數倍處,結構體的整體??就是所有最?對?數(含嵌套結構體中成員的對?數)的整數倍。

?

? ? ? ? 這樣一來,我們分析上兩個問題:


?

? ? ? ? 對于s1,先放入char類型,由于char類型是1個字節,小于8(VS默認值),所以直接放在0地址處。

? ? ? ? 值得一提,長度是1的char無論何時都不會浪費空間,它會直接頂著上一個數據的存儲空間放置。

? ? ? ? int型,大小4字節,小于8(VS默認值),所以放在sizeof(int)的整數倍的地址處,也就是4開始,到7結束。

? ? ? ? char 緊跟著int型;


????????由于最大對齊數是4,此時結構體的最小大小大于8,要滿足4的整數倍,那么這個結構體的大小向上取 是12。

? ? ? ? 對于s2?:

? ? ? ? 放入兩個char,一個int后的結構體最小大小正好是8,那么結構體總大小就是8。

?

?


練習:?

int main(int argc, char* argv[])
{struct tagTest1{short a;char d; long b;   long c;   };struct tagTest2{long b;   short c;char d;long a;   };struct tagTest3{short c;long b;char d;   long a;   };struct tagTest1 stT1;struct tagTest2 stT2;struct tagTest3 stT3;printf("%d %d %d", sizeof(stT1), sizeof(stT2), sizeof(stT3));return 0;

? ? ? ? 結果:?


?完~

未經作者同意禁止轉載

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

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

相關文章

力扣-151. 反轉字符串中的單詞

文章目錄 看下去&#xff0c;你一定可以理解此題&#xff0c;寫的簡單易懂力扣題目解題思路函數構成1.反轉函數2.消除掉多余空格函數 整體函數 看下去&#xff0c;你一定可以理解此題&#xff0c;寫的簡單易懂 力扣題目 給你一個字符串 s &#xff0c;請你反轉字符串中 單詞 …

京東商品詳情數據在數據分析行業中的重要性

京東商品詳情數據在數據分析行業中具有重要作用。這些數據提供了豐富的信息&#xff0c;可以幫助企業了解市場趨勢、消費者需求、產品表現以及運營策略等多個方面。 首先&#xff0c;京東商品詳情數據可以為企業提供市場趨勢分析的依據。通過觀察商品的銷售量、銷售額、價格等…

c語言:理解和避免野指針

野指針的定義&#xff1a; 野指針是指一個指針變量存儲了一個無效的地址&#xff0c;通常是一個未初始化的指針或者指向已經被釋放的內存地址。當程序嘗試使用野指針時&#xff0c;可能會導致程序崩潰、內存泄漏或者其他不可預測的行為。因此&#xff0c;在編程中需要特別注意…

Pandas中DataFrame對象的創建與常用屬性方法(第2講)

Pandas中DataFrame對象的創建與常用屬性方法(第2講) ??????? ??博主 侯小啾 感謝您的支持與信賴。?? ???????????????????????????????????????????????????????????????????????????…

智能優化算法應用:基于孔雀算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼

智能優化算法應用&#xff1a;基于孔雀算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼 文章目錄 智能優化算法應用&#xff1a;基于孔雀算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼1.無線傳感網絡節點模型2.覆蓋數學模型及分析3.孔雀算法4.實驗參數設定5.算法結果6.參考文獻7.MATLAB…

[足式機器人]Part2 Dr. CAN學習筆記-數學基礎Ch0-2 特征值與特征向量

本文僅供學習使用 本文參考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN學習筆記-數學基礎Ch0-2 特征值與特征向量 1. 定義1.1 線性變換1.2 求解特征值&#xff0c;特征向量1.3 應用&#xff1a;對角化矩陣——解耦Decouple 2. Summary 1. 定義 A v ? λ v ? A\vec{v}\lambd…

【網絡奇緣】- 計算機網絡|深入學習物理層|網絡安全

? &#x1f308;個人主頁: Aileen_0v0&#x1f525;系列專欄: 一見傾心,再見傾城 --- 計算機網絡~&#x1f4ab;個人格言:"沒有羅馬,那就自己創造羅馬~" 回顧鏈接&#xff1a;http://t.csdnimg.cn/ZvPOS 這篇文章是關于深入學習原理參考模型-物理層的相關知識點&…

Linux權限命令詳解

Linux權限命令詳解 文章目錄 Linux權限命令詳解一、什么是權限&#xff1f;二、權限的本質三、Linux中的用戶四、linux中文件的權限4.1 文件訪問者的分類&#xff08;人&#xff09;4.2 文件類型和訪問權限&#xff08;事物屬性&#xff09; 五、快速掌握修改權限的做法【第一種…

Spark-Streaming+Kafka+mysql實戰示例

文章目錄 前言一、簡介1. Spark-Streaming簡介2. Kafka簡介二、實戰演練1. MySQL數據庫部分2. 導入依賴3. 編寫實體類代碼4. 編寫kafka主題管理代碼5. 編寫kafka生產者代碼6. 編寫Spark-Streaming代碼總結前言 本文將介紹一個使用Spark Streaming和Kafka進行實時數據處理的示例…

實戰1-python爬取安全客新聞

一般步驟&#xff1a;確定網站--搭建關系--發送請求--接受響應--篩選數據--保存本地 1.拿到網站首先要查看我們要爬取的目錄是否被允許 一般網站都會議/robots.txt目錄&#xff0c;告訴你哪些地址可爬&#xff0c;哪些不可爬&#xff0c;以安全客為例子 2. 首先測試在不登錄的…

Docker Network(網絡)——8

目錄&#xff1a; Docker 為什么需要網絡管理Docker 網絡架構簡介 CNMLibnetwork驅動常見網絡類型 bridge 網絡host 網絡container 網絡none 網絡overlay 網絡docker 網絡管理命令 docker network createdocker network inspectdocker network connectdocker network disconne…

class072 最長遞增子序列問題與擴展【算法】

class072 最長遞增子序列問題與擴展【算法】 code1 300. 最長遞增子序列 // 最長遞增子序列和最長不下降子序列 // 給定一個整數數組nums // 找到其中最長嚴格遞增子序列長度、最長不下降子序列長度 // 測試鏈接 : https://leetcode.cn/problems/longest-increasing-subsequen…

830. 單調棧

?????? ??????830. 單調棧 - AcWing題庫 給定一個長度為 N 的整數數列&#xff0c;輸出每個數左邊第一個比它小的數&#xff0c;如果不存在則輸出 ?1?1。 輸入格式 第一行包含整數 N&#xff0c;表示數列長度。 第二行包含 N個整數&#xff0c;表示整數數列…

你知道MySQL中 group by 怎么優化嗎

更好的閱讀體驗&#xff0c;請點擊 YinKai s Blog。 ? 在 MySQL 中 group by 用于按照一個或多個列對結果集進行分組。在討論 group by 怎么優化之前&#xff0c;我們先來看看 group by 的執行流程&#xff0c;這樣我們才能對癥下藥。 group by 執行流程 ? 我們先用下面的 …

Ubuntu 18.04使用Qemu和GDB搭建運行內核的環境

安裝busybox 參考博客&#xff1a; 使用GDBQEMU調試Linux內核環境搭建 一文教你如何使用GDBQemu調試Linux內核 ubuntu22.04搭建qemu環境測試內核 交叉編譯busybox 編譯busybox出現Library m is needed, can’t exclude it (yet)的解釋 S3C2440 制作最新busybox文件系統 https:…

block-recurrent-transformer-pytorch 學習筆記

目錄 有依賴項1&#xff1a; 沒有依賴項&#xff0c;沒有使用例子 沒有依賴項2&#xff1a; 有依賴項1&#xff1a; GitHub - dashstander/block-recurrent-transformer: Pytorch implementation of "Block Recurrent Transformers" (Hutchins & Schlag et a…

gd32和stm32的區別

gd32和stm32的區別 現在的市場上有很多種不同類型的微控制器&#xff0c;其中比較常見的有兩種&#xff0c;即gd32和stm32。兩種微控制器都是中國和歐洲的兩個公司分別推出的&#xff0c;但是它們之間有很多區別&#xff0c;本文將會深入探討這些區別。 1.起源和歷史 gd32是…

2024年網絡安全競賽-Web安全應用

Web安全應用 (一)拓撲圖 任務環境說明: 1.獲取PHP的版本號作為Flag值提交;(例如:5.2.14) 2.獲取MySQL數據庫的版本號作為Flag值提交;(例如:5.0.22) 3.獲取系統的內核版本號作為Flag值提交;(例如:2.6.18) 4.獲取網站后臺管理員admin用戶的密碼作為Flag值提交…

udp多播組播

import socket ,struct,time# 組播地址和端口號 MCAST_GRP 239.0.0.1 MCAST_PORT 8888 # 創建UDP socket對象 sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # 綁定socket對象到本地端口號 # sock.bind((MCAST_GRP, MCAST_PORT)) …