網站首頁 編程語言 正文
一、本章重點
- 創建結構體
- typedef與結構體的淵源
- 匿名結構體
- 結構體大小
- 結構體指針
- 其他
二、創建結構體
先來個簡單的結構體創建
這就是一個比較標準的結構體
struct people
{
int age;
int id;
char address[10];
char sex[5];
};//不要少了分號。
需要注意的是不要少了分號。
那么這樣創建結構體呢?
struct phone
{
char brand[10];//品牌
int price;//價格
};
struct people
{
int age;
int id;
char address[10];
char sex[5];
struct phone;
};
很顯然,一個結構體是能夠嵌套另一個結構體的。
沒有這樣的設計,這樣做也行
struct people
{
int age;
int id;
char address[10];
char sex[5];
char phone_brand[10];
int phone_price;
};
但結構體中成員太多了是不利于我們后期的維護的,試問:假設有1000個成員,你能快速的找出你需要的成員嗎?當有了分塊的結構體,我們是能夠迅速的定位和查看的。
??結構體能夠嵌套另一結構體,那么結構體能否嵌套自己呢?
struct phone
{
char brand[10];
int price;
struct phone;
};
這樣做之后編譯器會給你一個報錯
原因是什么呢?
因為這個結構體的大小是未定義的,你能算出這個結構體的大小嗎?這是不可能的!
既然大小不能確定,那么當你用這個結構體去創建變量,編譯器該為這個變量開辟多大的空間呢?所有編譯器在設計之初便杜絕了這種可能。
在提一個問題,結構體是否可以嵌套自己的結構體指針呢?
struct people
{
int age;
int id;
char address[10];
char sex[5];
struct people* son[2];
};
答案是:可以
這里并不存在空間該分配多少的問題,因為struct?people*是指針類型,它的大小是確定的,在32位機器下是4字節,64為機器是8字節。
三、typedef與結構體的淵源
先上一段代碼
struct people
{
int age;
int id;
}a;//a代表什么?
int main()
{
a.age = 20;
printf("%d\n", a.age);
return 0;
}
提問:a代表什么?
其實我們可以這樣去看這個問題
struct people{int age;int id;} a;
int main()
{
a.age = 20;
printf("%d\n", a.age);
return 0;
}
對比int?b呢?
int b;
struct people{int age;int id;} a;
int main()
{
a.age = 20;
printf("%d\n", a.age);
return 0;
}
顯然,struct people{int age;int id;}代表的是結構體類型,就像整形類型一樣去創建變量。
那么這里的a就是結構體創建的變量。
這里也能明白結構體創建的最后為什么要保留分號。
那我們再看一段代碼:
typedef struct people
{
int age;
int id;
}a;
int main()
{
a.age = 20;
printf("%d\n", a.age);
return 0;
}
此時加上typedef,a還能當結構體創建的變量嗎?
顯然不行,此時編譯器會報錯。
?理解方式以上述一致。
typedef struct people{int age;int id;} a;
類似于
typedef struct people{int age;int id;} a;
typedef int b;
此時的a就是struct people{int age;int id;}
typedef的作用是把struct people{int age;int id;}這一類型重命名為a。
不知道你有沒有見過這樣的代碼
typedef struct people
{
int age;
int id;
}b,a,*c;
int main()
{
a a1;
b b1;
c c1 = &a1;
a1.age = 5;
b1.age = 6;
c1->age = 10;
printf("%d %d %d\n", a1.age, b1.age, c1->age);
return 0;
}
你知道運行結果嗎?
這里的b、a、c是什么呢?
這里我就不啰嗦了,a和b都是struct people{int age;int id;}結構體類型,c是struct people{int age;int id;}*? 結構體指針類型。
運行結果:
那么再次提升一下
typedef struct people
{
int age;
int id;
}b, a, c[20];
這里的b、a、c代表什么呢?
期待著你動手解決這一問題。
四、匿名結構體
這就是一個匿名的結構體
struct
{
int age;
int id;
};
int main()
{
struct p1;
p1.age = 10;
printf("%d\n", p1.age);
return 0;
}
匿名結構體能這樣創建結構體變量嗎?
此時編譯器會報錯
這樣的匿名結構體只能在創建結構體的時候定義好變量。
比如這樣
struct
{
int age;
int id;
}p1;
int main()
{
p1.age = 10;
printf("%d\n", p1.age);
return 0;
}
?接下來我們看下這段代碼
typedef struct
{
int age;
int id;
}people;
int main()
{
people p1;
p1.age = 10;
printf("%d\n", p1.age);
return 0;
}
這里我們重命名這個匿名結構體,即把這個結構體類型重命名為people。
那么我們自然可以用people類型來創建p1。也可創建p2、p3等等。
運行結果:
以下代碼合法嗎?
//匿名結構體類型
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
int main()
{
//在上面代碼的基礎上,下面的代碼合法嗎?
p = &x;
return 0;
}
警告: 編譯器會把上面的兩個聲明當成完全不同的兩個類型。 所以是非法的。
五、結構體大小
如何求結構體類型的大小?
這需要了解結構體成員在內存是怎么存儲的。
你知道下面這段代碼的運行結果嗎?
struct people
{
char a;
int b;
char c;
};
int main()
{
struct people p1;
printf("%d\n", sizeof(p1));//大小是6嗎?
return 0;
}
char是一字節大小
int是四字節大小
char是一字節大小
直接相加等于6
那么這個結構體的大小是6嗎?
但我們發現答案是12
這是為什么呢?
簡單來說編譯器為了讀取內存時提升效率和避免讀取出錯,它做了內存對齊的操作。
什么是內存對齊?
就是讓數據安排在合適的位置上所進行的對齊操作。
為什么要內存對齊?
- 一、移植原因
1.不是所有的硬件平臺都能訪問任意地址上的任意數據的;
2.某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常。
- 二、性能原因:
為了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。
對齊規則:
Windows中默認對齊數為8,Linux中默認對齊數為4
- 一:第一個數據成員從偏移地址為0的地方開始存放。
- 二:對齊數:等于默認對齊數與與該成員大小的較小值。
- 三:從第二成員開始,從它對齊數的整數倍的偏移地址開始存放。
- 四:最后結構體的大小需要調整為最大對齊數的整數倍。
最大對齊數:即所有成員對齊數中最大的對齊數。
struct people
{
char a;
int b;
char c;
};
解析:
第一個為char,直接放在偏移地址為0的位置處。
第二個為int,它的自身大小為4,比默認對齊數小,所以它的對齊數是4。
4是4的整數倍,所以在偏移地址為4處開始放數據。
第三個為char,自身大小為1,比默認對齊數小,它的對齊數是1。
8是1的整數倍,從偏移地址為8的位置開始放。
總大小為9,不是最大對齊數的整數倍
要浪費3個空間,調整后為12。
我們再看看下面這段代碼:
將char?和 int成員變量交換位置后,這結構體的大小還是12嗎?
struct people
{
char a;
char c;
int b;
};
int main()
{
struct people p1;
printf("%d\n", sizeof(p1));//大小是多少呢?
return 0;
}
解析:
第一個:直接從0處開始放
第二個是char:對齊數是1,1是1的整數倍,從偏移地址為1的位置開始放。
第二個是int:對齊數是4,4是4的整數倍,從偏移地址為4的位置開始放。
放好各個成員變量后,總大小是8,是最大對齊數(4)的整數倍,不需要調整。
因此這個結構體的大小是8.
再來看看下面這個如何?
struct people
{
char a;
int b;
short c[2];
char d;
};
int main()
{
struct people p1;
printf("%d\n", sizeof(p1));//大小是6嗎?
return 0;
}
解析:
第一個成員是char,直接放再0地址處。
第二個成員是int,對齊數是4,從偏移地址為4的位置處開始存放。
第三個成員是short[2],關于數組,它的對齊數是首元素的大小與默認對齊數的較小值,這里它的對齊數是2,然后從偏移地址為8處開始存放4個字節。
第四個成員是char,對齊數是1,直接放開12位置處。
總大小是13,最大對齊數是4,不是最大對齊數的整數倍,需要對齊到最大對齊數的整數倍,浪費3字節大小,對齊到16.
所以這個結構體的大小是16.
六、結構體指針
先創建一個結構體
struct people
{
char a;
int b;
};
然后用該結構體創建變量,再用結構體指針指向該變量。
int main()
{
struct people p1;
struct people* p = &p1;
return 0;
}
所謂結構體指針,即指向結構體的指針。
正如整形指針,即指向整形的指針。
訪問變量方式1:
int main()
{
struct people p1;
struct people* p = &p1;
p1.a = 'a';
p1.b = 10;
printf("%c %d\n", p1.a, p1.b);
return 0;
}
訪問變量方式2:
int main()
{
struct people p1;
struct people* p = &p1;
p->a = 'a';
p->b = 10;
printf("%c %d\n", p->a, p->b);
return 0;
}
訪問變量方式3:
int main()
{
struct people p1;
struct people* p = &p1;
(*p).a = 'a';
(*p).b = 10;
printf("%c %d\n", (*p).a, (*p).b);
return 0;
}
七、其他
結構體中還有兩個常見知識點:
一、位端
二、柔性數組
由于篇幅原因,下期會細細講解這兩個知識點
原文鏈接:https://blog.csdn.net/m0_62171658/article/details/123862064
相關推薦
- 2022-06-12 Unity?使用tiledmap解析地圖的詳細過程_C#教程
- 2022-04-21 C#使用Chart繪制曲線_C#教程
- 2022-10-04 混合棧跳轉導致Flutter頁面事件卡死問題解決_IOS
- 2022-12-03 C++通信新特性協程詳細介紹_C 語言
- 2022-07-15 Python中else怎么用?else的用法總結_python
- 2022-11-15 Python函數式編程之返回函數實例詳解_python
- 2022-10-03 Observing?KVO?Key-Value基本使用原理示例詳解_IOS
- 2023-05-17 一文速學Python+Pyecharts繪制樹形圖_python
- 最近更新
-
- 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同步修改后的遠程分支