? ? ? ? 今天我們來復習一下自定義類型.自定義類型大概分為結構體,枚舉,聯合體,數組這幾種.數組在之前就介紹過.今天我們來看下其他三種.
結構體
? ? ? ? 首先來看結構體.
??結構體類型的聲明
? ? ? ? 之前在操作符的地方簡單認識過結構體.下面我們回顧一下.
????????結構體回顧
????????結構是?些值的集合,這些值稱為成員變量。結構的每個成員可以是不同類型的變量。
? ? ? ? ?結構的特殊聲明--匿名結構體
????????上?的兩個結構在聲明的時候省略掉了結構體標簽(tag).
#include <stdio.h>struct
{int a;int b;
}x;
struct
{int a;int b;
}*p;
int main()
{x.a = 10;printf("%d", x.a);//x=*p;//err//不可以這樣進行賦值,雖然兩個結構體內部的結構相同,//但是匿名結構體只能用一次,所以編譯器會把這兩個看成不同類型//struct s;//err//并且無法用匿名結構體在之后創建變量return 0;
}
? ? ? ? 如果想使用多次可以進行typedef重命名.具體見下.
typedef struct
{int a;int b;
}ST;
int main()
{ST st;st.a = 10;printf("%d", st.a);return 0;
}
????????結構的自引用
? ? ? ? 其實是不可以的,如果這樣可以的?話,那么這個結構體的sizeof應該是多少呢?如果可以就沒法解答這個問題了,因為會出現套娃現象,結構體大小會變為無窮大.那么鏈表的節點是如何實現的呢?其實我們可以用結構體指針來代替直接在結構體中創建一個一樣的結構體.如下
? ? ? ? 如果要用typedef使結構體的名字更加簡單方便調用的話,在結構體內自引用使用指針時不要用typedef過的簡單名字.
??結構體內存對齊
? ? ? ? 我們已經了解了結構體的使用下面我們來了解一下結構體的大小.也就是結構體內存對齊.
? ? ? ? 雖然是浪費空間去換取時間,但是空間也不能大肆浪費,所以如何既滿?對?,?節省空間是需要學習的.
S1 和 S2 類型的成員?模?樣,但是 S1?所占空間要大于?S2.
修改默認對齊數
? ? ? ? 對于上述問題也可以通過修改默認對齊數來解決(一般修改的都是2的n次方的數).
#pragma pack(1)
struct S
{char a;int b;char c;
};
int main()
{struct S s;printf("%zd", sizeof(s));return 0;
}
//如果想還原
#pragma pack()
struct S
{char a;int b;char c;
};
int main()
{struct S s;printf("%zd", sizeof(s));return 0;
}
? 結構體傳參
typedef struct S
{char a;int b;char c;
}S;void test1(S s1)
{printf("%c %d %c\n", s1.a, s1.b, s1.c);
}
void test2(S* s2)
{printf("%c %d %c\n", s2->a, s2->b, s2->c);
}
int main()
{S s = {'y',10,'x'};test1(s);test2(&s);return 0;
}
? ? ? ? 上面兩個函數中test2要更好一點.
? ?結構體實現位段
????????什么是位段
????????位段的聲明和結構是類似的,有兩個不同
????????1. 位段的成員必須是 int 、 unsigned int 或 signed int ,在C99中位段成員的類型也可以選擇其他類型(char,一定要是整形大家庭中的).
????????2. 位段的成員名后邊有?個冒號和?個數字.(這個數字代表這個成員所占的比特位).
? ? ? ? 如下,一個簡單的例子
struct S
{
?? ?int a : 2;
?? ?int b : 3;
?? ?char c : 5;
};
? ? ? ? 既然知道了位段的大體結構,下面我們來看下大小?
struct S1
{char a : 2;char b : 3;char c : 5;
};
struct S2
{int a : 2;int b : 3;char c : 5;
};
int main()
{printf("%zd\n", sizeof(struct S1));printf("%zd\n", sizeof(struct S2));return 0;
}
? ? ? ? 輸出結果見下:
?
????????位段的內存分配
????????1. 位段的成員可以是 int unsigned int( signed int 或者是 char 等類型 int )
????????2. 位段的空間上是按照需要以4個字節或者1個字節( char )的?式來開辟的。并且在計算大小時也要遵循內存對齊.(如上求大小例子中的S2所示).
????????3. 位段涉及很多不確定因素,位段是不跨平臺的,注重可移植的程序應該避免使?位段。
????????位段的跨平臺問題
????????位段的應用
????????位段使用的注意事項?
????????位段的?個成員共有同?個字節,這樣有些成員的起始位置并不是某個字節的起始位置,那么這些位 置處是沒有地址的。內存中每個字節分配?個地址,?個字節內部的bit位是沒有地的。 所以不能對位段的成員使?&操作符,這樣就不能使?scanf直接給位段的成員輸?值,只能是先輸?放在?個變量中,然后賦值給位段的成員.
//struct S1
//{
// char a : 2;
// char b : 6;
// char c : 5;
//};
//int main()
//{
// struct S1 s;
// char ch;
// scanf("%c", &ch);
// s.b = ch;
// printf("%c", s.b);//在存進位段中時會發生截斷,不要用char類型實驗,這里打出來是截斷之后的
// return 0;
//}
//
//換為int實驗
struct S1
{int a : 2;int b : 18;int c : 5;
};
int main()
{struct S1 s;int ch = 0;scanf("%d%d",&s, &ch);s.b = ch;printf("%d %d\n", s.a, s.b);return 0;
}
聯合體
??聯合體類型的聲明
????????聯合體也是由?個或者多個成員構成,這些成員可以不同的類型.但是編譯器只為最?的成員分配?夠的內存空間.聯合體的特點是所有成員共?同?塊內存空間。所以聯合體也叫:共用體.給聯合體其中?個成員賦值,其他成員的值也跟著變化.
? ? ? ? 看一個簡答的例子
union U
{char a;int b;
};
int main()
{union U u;u.b =0x11223348;printf("%c\n", u.a);//48對應的ASCII碼表是Hreturn 0;
}
? ? ? ? 輸出結果見下?
??聯合體的特點
????????聯合的成員是共?同?塊內存空間的,這樣?個聯合變量的??,?少是最?成員的??(因為聯合 ?少得有能?保存最?的那個成員).
????????更加深入的理解一下
?
? ? ? ? 所以聯合體中所有元素的起始位置是相同的.
? 聯合體大小的計算?
????????聯合的???少是最?成員的??
????????當最大成員大小不是最大對?數的整數倍的時候,就要對?到最大對齊數的整數倍.
? ? ? ? 在計算之前看好是聯合體還是結構體,千萬不要搞混了.
union Un1
{char c[5];//數組的對齊數按照數組的類型的對齊數算int i;
};
//因為有int所以最大對齊數為4
union Un2
{short c[7];int i;
};
int main()
{//下?輸出的結果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}
? ? ? ? 輸出結果見下?
????????使?聯合體是可以節省空間的.
????????既然了解了聯合體那么我們來看下一個小練習吧.
寫?個程序,判斷當前機器是?端?還是?端(用到聯合體的知識)
union U
{int a;char b;
};
int main()
{union U u;u.a = 1;if (1 == (int)(u.b)){printf("小端\n");}else{printf("大端\n");}return 0;
}
枚舉類型
??枚舉類型的聲明
? ? ? ? 舉個例子:
enum Colour
{
?? ?RED,
?? ?GREEN,
?? ?BLUE,
};
? ? ? ? 驗證一下
enum Colour
{RED,GREEN,BLUE,
};
int main()
{printf("%d %d %d", RED, GREEN, BLUE);return 0;
}
enum Colour
{RED=2,GREEN,BLUE=5,
};
int main()
{printf("%d %d %d", RED, GREEN, BLUE);return 0;
}
? ? ? ? 如果一個給初始值后下面的沒有給則下面的值為上面值+1.
??枚舉類型的優點
????????簡單的注意一下第五點.?
??枚舉類型的使用
? ? ? ? 這里主要注意的是枚舉常量的賦值.
enum Colour
{RED=2,GREEN,BLUE=5,
};
int main()
{printf("%d %d %d", RED, GREEN, BLUE);// enum Colour c = 0;//在VS中不報錯,但是最好不要這樣做,枚舉類型就要用枚舉類型賦值enum Colour c = RED;//要用枚舉常量賦值return 0;
}
????????那是否可以拿整數給枚舉變量賦值呢?在C語?中是可以的,但是在C++是不?的,C++的類型檢查? 較嚴格
? ? ? ? 以上就是自定義類型的復習了,我們下次復習見.