結構體,是一個包含不同類型元素的集合。它和數組很像,數組是相同類型元素的集合。
1.結構體的聲明
例如描述一個學生:
struct stu
{
char name[20];
int age;
char sex[3];
char id[20];
};//分號不能丟
特殊的聲明:
在聲明結構的時候,可以不完全聲明。
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 stu
{
char name[20];
int age;
};
方式1:stu.name
方式2:stu->age
2.結構體變量的定義
struct P
{
int x;
double y;
}p1;//聲明類型的同時定義變量p1
struct P p2;//定義結構體變量p2
需要注意的是,結構體內的元素必須大於等於1個,也就是說,結構體內不能不放元素,至少要有一個元素。
3.結構體內存對齊
對齊規則:
1.第一個成員在與結構體變量偏移量爲0的地址處。
2.其他成員變量要對齊到對齊數的整數倍的地址處。
對齊數:編譯器默認的一個對齊數與該成員大小的較小值。
**vs中默認的值爲8
Linux中默認的值爲4**
3.結構體的總大小爲最大對齊數的整數倍。
4.如果嵌套了結構體的情況,嵌套的結構體對齊到自己最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數的整數倍。
爲什麼要內存對齊?
主要有兩個原因:
1.平臺原因:
不是所有的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常。
2.性能原因
數據結構(尤其是棧)應該儘可能在自然邊界上對齊。原因在於,爲了訪問未對齊的內存,處理器需要作兩次訪問;而對齊的內存僅需要訪問一次。
總的來說:
結構體的內存對齊是拿空間來換時間的做法。
4.位段
位段和結構體是類似的,有兩個不同:
1.位段的成員必須是int、unsigned int或signed int。
2.位段的成員名後面有一個冒號和一個數字。
比如:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
A就是一個位段類型。
位段的內存分配
1.位段的成員可以是int、unsigned int或signed int或者是char類型。
2.位段的空間上是按照需要以4個字節(int)或者1個字節(char)的方式來開闢的。
3.位段涉及很多不確定因素,位段是不跨平臺的,注意可移植的程序一個避免使用位段。
5.枚舉
枚舉,顧名思義就是一一列舉。
枚舉定義:
enum color
{
red,
green,
blue,
}
枚舉的優點
1.增強代碼的可讀性和可維護性
2.根#define定義的標識符比較,枚舉有類型檢查,更加嚴謹。
3.防止了命名污染
4.便於調試
5.使用方便,一次可以定義多個變量
6.聯合
聯合體的特徵就是,聯合體內的成員共用一塊內存空間,所以聯合體也叫共用體。
聯合體聲明
union Un
{
char c;
int i;
};
聯合體變量的定義
union Un un;
聯合的特點
聯合體共用一塊內存空間,這樣一個聯合變量的大小,至少是最大成員的大小。
當聯合體最大成員的大小不是最大對齊數的整數倍的時候,就要對齊到最大對齊數的整數倍。