1.C語言中的結構體
1.1 定義
結構體是由一系列相同或不同類型的變量組成的集合。
struct 結構體名{ //struct為關鍵字,“結構體名”為用戶定義的類型標識。
數據類型1 成員名1; //{ }中是組成該結構體的成員,其中數據類型可以是C語言所允許的任何數據類型。
數據類型2 成員名2;
...
數據類型n 成員名n;
};
1.2 結構體的內存分配(方法一)
結構體在內存中分配一塊連續的內存,但結構體內的變量並不一定是連續存放的,這涉及到內存對齊。
原則1 數據成員對齊規則:結構(struct或聯合union)的數據成員,第一個數據成員放在offset為0的地方,以后每個數據成員存儲的起始位置要從該成員大小的整數倍開始(比如int在32位機為4字節,則要從4的整數倍地址開始存儲)。
原則2 結構體作為成員:如果一個結構里有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍地址開始存儲。(struct a里存有struct b,b里有char,int,double等元素,那b應該從8的整數倍開始存儲。)
原則3 收尾工作:結構體的總大小,也就是sizeof的結果,必須是其內部最大成員的整數倍,不足的要補齊。
例1.
struct A{ struct B{ int a; char b; char b; int a; short c; short c; }; }; sizeof(A) = 8; int為4,char為1,short為2,這里用到了原則1和原則3。 sizeof(B) = 12; char為1,int為4,short為2,怎么會是12?還是原則1和原則3。 a b c A的內存布局:1111, 1*, 11 b a c B的內存布局:1***, 1111, 11**
其中星號*表示填充的字節。
A中,b后面為何要補充一個字節?因為c為short,其起始位置要為2的倍數,就是原則1。c的后面沒有補充,因為b和c正好占用4個字節,整個A占用空間為4的倍數,也就是最大成員int類型的倍數,所以不用補充。
B中,b是char為1,b后面補充了3個字節,因為a是int為4,根據原則1,起始位置要為4的倍數,所以b后面要補充3個字節。c后面補充兩個字節,根據原則3,整個B占用空間要為4的倍數,c后面不補充,整個B的空間為10,不符,所以要補充2個字節。
例2.
struct A{ struct B{ int a; char e[2]; double b; int f; float c; double g; }; short h; struct A i; }; sizeof(A) = 24; int為4,double為8,float為4,總長為8的倍數,補齊,所以整個A為24。 sizeof(B) = 48; 看看B的內存布局。 e f g h B的內存布局:11* *, 1111, 11111111, 11 * * * * * *, i 1111* * * *, 11111111, 1111 * * * *
i其實就是A的內存布局。根據原則2,i的起始位置要為8的倍數,所以h后面要補齊。
1.3 結構體的內存分配(方法二)
struct的內存大小為每個數據內存的加和,首先按照最大的數據類型進行單個分配,如果前一個數據占用不了所有的內存,而剩下的內存可以放下下一個數據,則第二個數據不另外分配內存(但是地址必須是從這個數據類型大小的整數倍開始,看下面的struct C),否則重新分配一個最大類型的內存。(個人覺得這種方法比較好理解!)
例3.
struct A{ struct B{ struct C{ int a; int a; int a; char b; double b; char b; double c; char c; short c; }; }; char d; }
對於結構體A:
因為A中最大的數據類型是double,占8個字節。所以系統先分配8個字節用來放int,結果int只需要4個就夠了,然后剩下的4個字節中的1個可以用來放后面的char,碰到double c時,因為此時的3個字節不能存下,所以再分配了一個8個字節來存放double c。因此A占用16個字節。
對於結構體B:
系統碰到int分給他8個字節存放,碰到double時,剩下的4個字節不足以存放,所以再分配了8個字節,再遇到char時又分配了8個字節,這樣B共分配了24個字節。(系統其實是浪費了5個字節的空間)
比較A和B,只有變量定義的順序不一樣,結果占用的內存空間也不一樣。所以,結構體里面最好按照類型從小到大的順序來排列,以免浪費空間。
對於結構體C:
按照上述方法,最大的數據類型是int,占4個字節,系統先分配4個字節(0~3);再分配4個字節(4~7),存放char b;short c占2個字節,但是必須從2的整數倍開始,所以應當分配(6~7),中間空余1個字節;char d占1個字節,但是上次分配的4字節用完了,所以需要再分配4個字節存放char d,d只占用1個字節,所以剩下3個字節空閑。sizeof(struct C)=12。
2. C++中的結構體與類的區別
C中的結構體不允許有函數,而C++中的結構體允許。
類與結構體在C++中只有兩點區別,除此這外無任何區別。
1)class中默認的成員訪問權限是private的,而struct中則是public的。
2)從class繼承默認是private繼承,而從struct繼承默認是public繼承。
3. 聯合union
3.1 定義
聯合(又叫共用體)是一種特殊形式的變量,使用關鍵字union來定義 ,它的聲明與變量定義與結構體十分相似。其形式為:
union 聯合名
{
數據類型 成員名;
數據類型 成員名;
...
} 變量名;
聯合表示幾個變量共用一個內存位置,在不同的時間保存不同的數據類型和不同長度的變量。在union中,所有的聯合成員共用一個空間,並且同一時間只能儲存其中一個成員變量的值。
3.2 聯合的內存分配
Union的大小為其內部所有變量的最大值,並且按照類型最大值的整數倍進行內存對齊。
union A union B union C union D { { { { char c[10]; char c[10]; char c[10]; char c; char cc1; int i; double d; int i; }u1; }u2; }u3; double d; }u4;
union A :首先按照char c[10]分配10個字節,然后按照char的1個字節對齊,最終sizeof(u1)=10;
union B :首先按照char c[10]分配10個字節,然后按照int的4個字節對齊,最終sizeof(u2)=12; (大於等於10且能被4整除的最小的數,即12)
union C :首先按照char c[10]分配10個字節,然后按照doube的8個字節對齊,最終sizeof(u3)=16;(大於等於10且能被8整除的最小的數,即16)
union D:按照double分配8個字節,最終sizeof(u4)=8;
3.3 應用
在C/C++程序的編寫中,當多個基本數據類型或復合數據結構要占用同一片內存時,我們要使用聯合體;當多種類型,多個對象,多個事物只取其一時(我們姑且通俗地稱其為“n 選1”),我們也可以使用聯合體來發揮其長處。
union myun { struct { int x; int y; int z; }u; int k; }a; int main() { a.u.x =4; a.u.y =5; a.u.z =6; a.k = 0; printf("%d %d %d\n",a.u.x,a.u.y,a.u.z); return 0; }
union類型是共享內存的,以size最大的結構作為自己的大小,這樣的話,myun這個結構就包含u這個結構體,而大小也等於u這個結構體的大小,在內存中的排列為聲明的順序x,y,z從低到高,然后賦值的時候,在內存中,就是x的位置放置4,y的位置放置5,z的位置放置6,現在對k賦值,對k的賦值因為是union,要共享內存,所以從union的首地址開始放置,首地址開始的位置其實是x的位置,這樣原來內存中x的位置就被k所賦的值代替了,就變為0了,這個時候要進行打印,就直接看內存里就行了,x的位置也就是k的位置是0,而y,z的位置的值沒有改變,所以應該是0,5,6。
4.結構體和聯合的區別:
1)聯合和結構體都是由多個不同的數據類型成員組成,但在任何同一時刻,聯合只存放了一個被選中的成員,而結構體的所有成員都存在。
2)對於聯合的不同成員賦值,將會對其它成員重寫,原來成員的值就不存在了,而對於結構體的不同成員賦值是互不影響的。