結構體+列舉+聯合體
- 結構體
- 結構體的宣告
- 結構體的嵌套+鏈表
- 結構體變數的初始化
- 結構體的記憶體對齊
- 一、首先得掌握結構體的對齊規則
- 二、一些具體的例子
- 為什么存在記憶體對齊?
- 位段
- 位段的記憶體保存
- 列舉
- 列舉的優點
- 聯合體
- 聯合體內的空間使用
- 聯合體大小的計算
結構體
結構體的宣告
struct Stu
{
char name[20];//名字
int age;//年齡
char sex[5];//性別
char id[20];//學號
};//分號不能丟
需要注意的是結構體可以使用匿名宣告,但這種宣告只能只能使用一次,相當于s是一個變數,不再是一個型別,
struct
{
int a;
char b;
float c; }x;
struct
{
int a;
char b;
float c; }a[20], *p;
結構體的嵌套+鏈表
錯誤的創建形式,這種創建方法導致結構體的大小是一個未知值
struct node{
int data;
struct node next;
};
正確的創建方法:(以鏈表為例)
struct Node
{
int data;
struct Node* next;
};
其實這是一個先有雞還是先有蛋的問題:
typedef struct
{
int data;
Node* next; }Node;//這樣寫,做成Node這個型別產生先有雞還是先有蛋的困惑
//解決方案:
typedef struct Node
{
int data;
struct Node* next; }Node;
結構體變數的初始化
struct Stu{
int age;
char name[10];
char sex[3];
};
struct Stu a={10,"Alex","F"};
結構體的記憶體對齊
一、首先得掌握結構體的對齊規則
- 第一個成員在與結構體變數偏移量為0的地址處,
- 其他成員變數要對齊到某個數字(對齊數)的整數倍的地址處,
對齊數 = 編譯器默認的一個對齊數 與 該成員大小的較小值,
其中:VS中默認的值為8,Linux中的默認值為4 - 結構體總大小為最大對齊數(每個成員變數都有一個對齊數)的整數倍,
- 如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍,
二、一些具體的例子
//練習1
struct S1
{
char c1;//對齊數1 占據1
int i;//對齊數4 占據4-8
char c2;//對齊數1 占據9
};
printf("%d\n", sizeof(struct S1));//最終為4的倍數即為12

更多的例子
//練習2
struct S2
{
char c1;//占據1
char c2;//占據2
int i;//占據4-8
};
printf("%d\n", sizeof(struct S2));//共8個位元組
//練習3
struct S3
{
double d;//占據1-8
char c;//占據9
int i;//占據12-16
};
printf("%d\n", sizeof(struct S3));//共16個位元組
//練習4-結構體嵌套問題
struct S4
{
char c1;//占據1
struct S3 s3;//占據8-24,因為vs環境下默認值為8
double d;//占據25-32
};
printf("%d\n", sizeof(struct S4));//共32位元組
為什么存在記憶體對齊?
大部分的參考資料都是如是說的:
- 平臺原因(移植原因): 不是所有的硬體平臺都能訪問任意地址上的任意資料的;某些硬體平臺只能在某些地址
處取某些特定型別的資料,否則拋出硬體例外, - 性能原因: 資料結構(尤其是堆疊)應該盡可能地在自然邊界上對齊,原因在于,為了方位未對齊的記憶體需要兩次記憶體訪問,而對齊的只需要一次
本質上就是利用空間換取時間,為了更加節省空間,我們需要在開辟結構體時,注意將占空間小的變數放在一起,
位段
位段的成員必須是int,unsigned int或signed int,char型別,位段的成員名后有一個冒號和一個數字,
struct A
{
int _a:2;//此處2代表2個位元位,下同
int _b:5;
int _c:10;
int _d:30;
};
位段本質上是將位元組拆分為位元位使用
位段的記憶體保存
以上文代碼為例,a+b+c共占17個位元位<32個位元位=4個位元組
而在vs編譯環境下,由于a+b+c+d會超過32個位元位,所以32-17=15個剩余的位元位棄之不用,單獨開辟一個int用于存放30個位元位的d

列舉
enum Day
{
Mon,//0
Tues,//1
Wed,//2
Thur,//3
Fri,//4
Sat,//5
Sun//6
};
列舉常量中的成員初始賦值均從0開始
enum Day
{
Mon,//0
Tues,//1
Wed=10,//10
Thur,//11
Fri,//12
Sat,//13
Sun//14
};
若對其中的某一個值賦值,那后面的未定義的+1
列舉的優點
我們可以使用#define 定義常量,為什么非要使用列舉? 列舉的優點:
- 增加代碼的可讀性和可維護性
- 和#define定義的識別符號比較列舉有型別檢查,更加嚴謹,
- 防止了命名污染(封裝)
- 便于除錯
- 使用方便,一次可以定義多個常量
聯合體
聯合體的特點是,所有成員共用同一塊空間
union Un
{
int i;
char c;
};
union Un un;

聯合體內的空間使用
// 下面輸出的結果是一樣的嗎?
printf("%d\n", &(un.i));
printf("%d\n", &(un.c));
//下面輸出的結果是什么?
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n",un.i);//根據小段應輸出為11223355
聯合體大小的計算
1.聯合的大小至少是最大成員的呢大小,
2.當最大成員大小不是最大對齊數的整數倍的時候,就要對齊到最大對齊數的整數倍,
#需要注意的是char c[5]類似的陣列對齊數仍然是陣列中一個元素的對齊數,對char c[5]即為1

故此圖中聯合體大小為8
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/267455.html
標籤:其他
下一篇:strstr函式的學習和模擬實作
