結構體struct && 聯合union


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)對於聯合的不同成員賦值,將會對其它成員重寫,原來成員的值就不存在了,而對於結構體的不同成員賦值是互不影響的。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM