結構體、列舉和聯合

2021-03-10 12:00:53

結構體

結構體的宣告

struct Book
{
    //成員
    //結構體的成員可以是不同型別的變數
	char name[20];
	char author[20];
	short price;
}b1;//全域性變數

結構體的自參照

這是一個錯誤的寫法

struct Node
{
	int data;
	struct Node n;
}

應該這樣去寫(連結串列)

struct Node
{
	int data;//資料域
	struct Nade* next;//指標域
};

結構體變數的定義和初始化

舉一個例子,內涵結構體的巢狀

struct S
{
	int  a;
	int b;
	double c;
};
struct A
{
	char q;
	struct S s;//巢狀
	short ss;
};
int main()
{
	struct A a = { "d",{11,22,33.3},4 };//初始化
	printf("%1f\n", a.s.c);
	return 0;
}

結構體記憶體對齊

結構體在計算大小時,會發生對齊
結構體對齊的規則:
1、第一個成員在與結構體變數偏移量為0的地址處。
其他成員變數要對齊到某個數位(對齊數)的整數倍的地址處。
2、對齊數 = 編譯器預設的一個對齊數與該成員大小的較小值。VS中預設的值為8,Linux中的預設值為4
3、結構體總大小為最大對齊數(每個成員變數都有一個對齊數)的整數倍。
4、如果巢狀了結構體的情況,巢狀的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含巢狀結構體的對齊數)的整數倍。

#include<stdio.h>
struct S1
{
	char c1;//對齊數:1
	int i;//對齊數:4
	char c2;//對齊數:1
};
int main()
{
	struct S1 s1;
	printf("%d\n", sizeof(s1));//輸出值要是4的倍數,所以為12
	return 0;
}

在這裡插入圖片描述

struct S1
{
	char c1;//1
	char c2;//1
	int i;//4
};

將佔用記憶體小的成員放在一起,可以有效的避免記憶體的浪費
在這裡插入圖片描述
為什麼記憶體要對齊?
1、平臺原因(移植原因): 不是所有的硬體平臺都能存取任意地址上的任意資料的;某些硬體平臺只能在某些地址
處取某些特定型別的資料,否則丟擲硬體異常。
2、效能原因: 資料結構(尤其是棧)應該儘可能地在自然邊界上對齊。原因在於,為了方位未對齊的記憶體需要兩次記憶體存取,而對齊的只需要一次
就是那空間換取時間

修改預設對齊數

結構體在對齊方式不合適的時候我們可以自自己修改預設對齊數

#pragma pack(1)//設定預設對齊數
struct S1
{
	char c1;//1
	int i;//4
	char c2;//1
};
#pragma pack()//恢復預設對齊數
//輸出結果為6

列舉

列舉型別的定義

enum Sex//型別
{
    //列舉型別可能取的值
	MALE,//0
	FEMALE,//1
	SECRET//2
};
enum RGB
{
	RED,//0
	GREEN=5,//5
	BLUE//6
};

初始值預設為0,一次遞加1,也可以賦值

列舉的優點

1、增加程式碼的可讀性和可維護性
2、和#define定義的識別符號比較列舉有型別檢查,更加嚴謹。
3、防止了命名汙染(封裝)
4、便於偵錯
5、使用方便,一次可以定義多個常數

列舉的使用

enum RGB
{
	RED=1,
	GREEN=3,
    BLUE=5
};
enum RGB clr = GREEN;//只能拿列舉常數給列舉變數賦值,才不會出現型別的差異
clr=5

聯合(共用體)

i和c會佔用同一塊i空間

union Un
{i
	char c;//1
	int i;//4
};
union Un u;
printf("%d\n", sizeof(u));//值為4

聯合大小的計算

1、聯合的大小至少是最大成員的大小。
2、當最大成員大小不是最大對齊數的整數倍的時候,就要對齊到最大對齊數的整數倍

union U
{
	char arr[6];//6  對齊數為1
	int i;//4   對齊數為4
};
int main()
{
	union U u;
	printf("%d\n", sizeof(u));//輸出為8
	return 0;
}