C語言中有不少的基礎數據類型,除了這些咱們能夠經過一個結構體來把一部分基礎數據類型整合爲一個新的自定義類型。node
struct 結構體的標籤 { 成員1 ; 成員2 ; ..... }; // 最後用一個分號來表示結束
結構體的標籤 : 用來區分各個不一樣類型的結構體 (也能夠省略)。
成 員: 指的是該結構體內部的數據,能夠是任何數據類型。也但是結構體數組
struct node { int a ; char c ; double d ; }; int main(int argc, char const *argv[]) { //定義結構體 --> 分配內存空間 struct node a ; }
注意:
1.只有結構體被定義時纔會被分配內存空間,結構體聲明並不會分配內存空間;
2.定義結構體的步驟:
a.分配一片內存名字叫 a
b.該內存中須要存放一個結構體
c.分被存放的是 int a , char c ,double d
字體
結構體與普通的變量都是同樣的,都設計涉及,初始化,賦值,取值,傳值等等操做。因爲結構體中的成員類型各有不一樣所以有兩種初始化獲得方法:
1.普通初始化
寫起來方便,可是改起來一點都不方便。
2.指定成員初始化
寫起來雖然累一點點, 可是若是結構體在後期有更新迭代,不會有初始化的效果。ui
//1.普通初始換 struct node c ={ 100 , 'M' , 3.1456676 } ; //2.指定成員初始化 struct node d = { .a = 998, // . 稱爲成員引用符 .c = 'K', .d =2345.21345 };
注意:
1.指定成員初始化:
a.成員的次序或數量的變化不會致使初始化有邏輯問題;
b.能夠初始化一部分紅員;
c.若是結構體新增成員,該初始化語句依然可用。操作系統
因爲結構體內部包含的成員不止一個,因此說須要使用 . 結構體成員的引用符來訪問其中指定的成員。設計
//結構體變量.結構體成員 printf("a:%d \t c:%c \t d:%lf\n", d.a, d.c , d.d ); d.a = 123 ; d.c = 'M'; d.d = 3.14; printf("a:%d \t c:%c \t d:%lf\n", d.a, d.c , d.d );
結構體數組與其餘的普通變量的數組並無差異,只不過他的數組內容爲一個一個的結構體。指針
struct node arr [10]; arr[0].a = 200; arr[0].c = 'N'; arr[0].d = 889.43;
結構體指針
結構體指針與其餘指針沒有差異,只不過其指向的是一個結構體。code
struct node * p ; p = &d ; printf("p->a:%d \t p->c:%c \t p->d:%lf\n", p->a, p->c , p->d );
注意:
1.普通的結構體成員引用使用 .;
2.指針的結構體成員應用使用 ->。blog
struct node { int a ; char c ; double d ; }; //變形 1 struct node { int a ; char c ; double d; }Even, GEC; // 在聲明結構體的時候順便定義兩個結構體變量 Even.a = 100 ; Even.c = 'C'; Even.d = 12312.234; printf("%d\t%c\t%lf\n" , Even.a , Even.c , Even.d);
//變形 2 struct {// 結構體的標籤能夠省略 ,可是省略的話之後無法定義更多的此類型結構體 int a ; char c ; double d; }Jacy; // 在聲明結構體的時候順便定義一個結構體變量 Jacy.a = 200 ; Jacy.c = 'A'; Jacy.d = 123.2; printf("%d\t%c\t%lf\n" , Jacy.a , Jacy.c , Jacy.d); //示例 struct CuiHua { int a ; char c ; double d ; struct { char * p ; char arr[32]; }Jacy; // 在聲明結構體的時候順便定義個結構體變量 }Even,GEC;// 在聲明結構體的時候順便定義兩個結構體變量 struct CuiHua hua = { .a = 1024 , .c = 'B' , .d = 123.123, .Jacy.p = "Hello",//p指向的是數據段中的 Hello 的地址 .Jacy.arr = "GZ2069" // 數組arr 屬於棧空間, 它內部存放了"GZ2069" }; printf("a:%d\t c:%c\t d:%lf\t p:%s\t arr:%s\n", hua.a,hua.c,hua.d,hua.Jacy.p, hua.Jacy.arr); hua.Jacy.p=malloc(32);//申請一篇堆空間大小爲32字節讓P指向hello strncpy(hua.Jacy.p , "hello" , 32 ); hua.Jacy.arr[0] = 'g'; hua.Jacy.arr[1] = 'z'; printf("a:%d\t c:%c\t d:%lf\t p:%s\t arr:%s\n", hua.a,hua.c,hua.d,hua.Jacy.p,hua.Jacy.arr);
// 變形 3 [ 推薦使用 ] typedef struct CuiHua { int num ; char *name ; char class[32]; }stu_info,*stu_info_p; //使用typedef 給結構體取別名 // stu_info 等同於 struct CuiHua //stu_info_p 等同於 struct CuiHua * int main(int argc, char const *argv[]) { stu_info a ; // 定義一個普通的結構體變量 a.num = 100 ; a.name = calloc(1 , 32 ); strncpy(a.name, "張全蛋",32); //注意拷貝以前必須分配空間給a.name。 strncpy(a.class, "GZ206666",32); printf("Num:%d\tName:%s\tClass:%s\n" ,a.num,a.name,a.class); stu_info_p c=calloc(1,sizeof(stu_info));//定義一個結構體指針變量 (*c).num = 200 ; c->name = calloc(1,32); strncpy( c->name, "張半蛋" , 32); strncpy(c->class, "GZ206667" , 32); printf("Num:%d\tName:%s\tClass:%s\n",c->num,c->name,c->class); return 0; }
指CPU一次性從內存中獲取的數據大小。32位cpu一次性處理4字節2進制數,64位計算機一次性處理8字節2進制數。排序
CPU字長肯定以後就能夠肯定咱們的CPU每一次在讀、寫內存的時候都是肯定大小 ,假設是32位系統,那麼每一次讀、寫內存時 ,都是按照4字節進行操做。
若是是沒有對齊的狀況下,須要讀取8字節則最多須要讀取3次才能夠把全部數據讀取完整。若是是對齊的狀況下只須要讀取兩次。
因此,若是地址沒有對齊CPU在操做時須要浪費更多的時間,能夠犧牲內存來提升效率。但也能夠犧牲效率來提升內存。
變量的地址值,能被M值整除。
char c ; // 大小 1 字節 , M值 1 short s ; // 大小 2 字節 , M值 2 int i ; // 大小 4字節 , M值 4 double d ;// 大小 4字節 , M值 4 printf("a:%p\n" , &a ); printf("s:%p\n" , &s ); printf("i:%p\n" , &i ); printf("d:%p\n" , &d ); ```
注意:
1.若是變量的尺寸小於 4 字節,那麼該變量的 m 值等於變量的長度;
2.若是變量的尺寸大於等於 4 字節,則一概按 4 字節對齊;
3.若是變量的 m 值被人爲調整過,則以調整後的 m 值爲準。
char c __attribute__((aligned(4))) ; // 手動干預通常只能往大的設置不能夠設置更小
注意:
1.__attribute__是GNU特定的語法,屬於C語言的拓展
2.__attribute__寫法注意 左右兩邊都是兩個下劃線右邊有兩組括號 (( ))
3.((aligned(4)))一個變量M值只能被提升不能夠下降
結構體的M值取決於結構體中最大成員的M值。結構體的對長字節取決於,結構體中最長字節和系統字長中最短的那個。
typedef struct CuiHua { int num ; // 4 char c1 ; // 1 char *name ; // 8 char c2 ; // 1 char c3 ; // 1 double d ; // 4 char c4 ; // 1 }stu,* p_stu; int main(int argc, char const *argv[]){ stu a ; printf("&a:%p\n" , &a); printf("&a.num:%p\n" , &a.num); printf("&a.name:%p\n" , &a.name); printf("&a.c1:%p\n" , &a.c1); printf("&a.c2:%p\n" , &a.c2); printf("&a.c3:%p\n" , &a.c3); printf("&a.c4:%p\n" , &a.c4); printf("&a.d:%p\n" , &a.d); printf("sizeof(a):%ld\n",sizeof(a)); //輸出40 return 0; }
如上圖所示,在64位系統下結構體a佔40個大小,結構體最大M爲8,字體字長也爲8,因此結構體M爲8。安裝結構體中變量定義的方式排序,
每一個變量的M值,必須能被變量的起始地址整除,因此獲得如上圖所示的存儲方式,每種顏色表明一個變量。
一樣一份代碼在不一樣的操做系統下(系統位數),須要考慮可移植性的問題,如數據尺寸的變化,存儲位置的變換
//方法1 統一壓實結構體成員: struct CuiHua { int num ; // 4 char c1 ; // 1 char *name ; // 8 char c2 ; // 1 char c3 ; // 1 double d ; // 4 char c4 ; // 1 }__attribute__((packed)); //把結構體進行壓實,不考慮按照順序排列了,能多擠就多擠,固然變量的起始地址仍是會被M整除,該結構體大小爲24 struct CuiHua { int num __attribute__((aligned(4))); // 4 char c1 __attribute__((aligned(1))) ; // 1 char *name __attribute__((aligned(8))); // 4 char c2 __attribute__((aligned(1))); // 1 char c3 __attribute__((aligned(1))); // 1 double d __attribute__((aligned(8))); // 4 }