和黛玉學編程呀,大家一起努力呀.............
?
結構體類型的聲明
?回顧一下
struct tag
{
member-list;
}variable-list;
?創建和初始化
我們知道,在C語言中,對于一些數據是必須初始化的,但是結構體怎么創建并且初始化呢?很簡單,直接賦值上就好了
?
#include <stdio.h>
struct Stu
{
char name[20]; //名字
int age; //年齡
char sex[5]; //性別
char id[20]; //學號
};
int main()
{
//按照結構體成員的順序初始化
struct Stu s = { "張三", 20, "男", "20230818001" };
printf("name: %s\n", s.name);
printf("age : %d\n", s.age);
printf("sex : %s\n", s.sex);
printf("id : %s\n", s.id);
//按照指定的順序初始化
struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "?
printf("name: %s\n", s2.name);
printf("age : %d\n", s2.age);
printf("sex : %s\n", s2.sex);
printf("id : %s\n", s2.id);
return 0;
}
結構體的特殊聲明?:
在聲明結構體的時候可以不完全聲明,也就是在struct后面不寫東西,比如上面的把Stu去掉?
結構體的自引用?
? 遞歸里面我們知道它用到了自己,那結構體可以包含一個類型為該結構本身的成員嗎??
來看一下吧
struct Node
{int data;struct Node* next;
};
結構體的內存對齊?
?對齊規則:
1.結構體的第?個成員對?到和結構體變量起始位置偏移量為0的地址處
2.其他成員變量要對?到某個數字(對?數)的整數倍的地址處對?數=編譯器默認的?個對?數與該成員變量??的較?值。(VS 中默認的值為 8?
Linux中gcc沒有默認對?數,對?數就是成員??的??)3.結構體總??為最?對?數(結構體中每個成員變量都有?個對?數,所有對?數中最?的)的整數倍。
4.如果嵌套了結構體的情況,嵌套的結構體成員對?到??的成員中最?對?數的整數倍處,結構體的整體??就是所有最?對?數(含嵌套結構體中成員的對?數)的整數倍?
看那么多不如找代碼來練習一下就知道啦
?1.
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
在vs上默認值是8?
對于C1,從0開始,然后對于i,它對齊數是4?對?數=編譯器默認的?個對?數與該成員變量??的較?值。
然后就從4開始對齊,他是int類型,占4個字節,占到7,
對于C2,對齊數是1,占到8,這個時候大小為9,從0到8也就是9個格子啦,這是可能會判斷錯的,所以最好畫圖解決
但是由于對齊規則(結構體總??為最?對?數(結構體中每個成員變量都有?個對?數,所有對?數中最?的)的整數倍。),在這個結構體最大對齊數為4,整數倍并且比9大的也就是12啦
?
?
?
?
如果我把結構體里面的內容換一個位置呢,結果又會怎么樣呢?
看代碼:
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));
我們再畫圖,c1從0?開始,c2的對齊數是1,從開始的一個字節,然后i的對齊數是4,從4開始4個字節,到7為止,現在大小是8,剛好是最大對齊數的整數倍,所以答案就是8
?
為什么要內存對齊呢
首先:?不是所有的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常
然后:數據結構(尤其是棧)應該盡可能地在?然邊界上對?。原因在于,為了訪問未對?的內存,處理器需要作兩次內存訪問;
總之有那么一個說法,結構體對齊就是拿空間換取時間的做法
在設計結構體的時候,我們為了節省空間又滿足對齊規則,所以盡量把占空間小的成員集中在一起,上面的兩個例子已經可以說明啦
修改默認對齊數?
上面說到,在vs上默認對齊數是8,但是我不想對齊數是8應該怎么修改呢,#pragma 這個預處理指令,可以改變編譯器的默認對?數。
#include <stdio.h>
#pragma pack(1) //設置默認對?數為1
struct S
{
char c1;
int i;
char c2;
};
#pragma pack() //取消設置的對?數,還原為默認
int main()
{
printf("%d\n", sizeof(struct S));
return 0;
}
?注意:結構體傳參的時候,最好傳的是地址,也就是需要使用到指針
結構體實現位段
什么是位段
1. 位段的成員必須是 int、unsigned int 或signed int ,在C99中位段成員的類型也可以
選擇其他類型。
2. 位段的成員名后邊有?個冒號和?個數字。
這個位段是為了節省空間
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
?這個時候A就是一個位段類型
這個2,5,10,34是比特的意思,加起來是47比特,?然后8是兩個整型,可以放下47比特
位段的內存分配?
1. 位段的成員可以是 int ?unsigned int? signed int 或者是 char 等類型?
2. 位段的空間上是按照需要以4個字節( int )或者1個字節( char )的?式來開辟的。
3. 位段涉及很多不確定因素,位段是不跨平臺的,注重可移植的程序應該避免使?位段。
?跟結構相?,位段可以達到同樣的效果,并且可以很好的節省空間,但是有跨平臺的問題存在
??位段使?的注意事項:
位段的?個成員共有同?個字節,這樣有些成員的起始位置并不是某個字節的起始位置,那么這些位
置處是沒有地址的。內存中每個字節分配?個地址,?個字節內部的bit位是沒有地址的。?
所以不能對位段的成員使?&操作符,這樣就不能使?scanf直接給位段的成員輸?值,只能是先輸?
放在?個變量中,然后賦值給位段的成員。
然后就到這里啦,你能看到這里,你已經很厲害啦,希望這些知識對你有所幫助啦,干完C語言然后我們就需要學習數據結構啦,這篇也算是數據結構里面的內容哦?
?
?
?