結構體對齊
1 C語言裏可以在一個存儲區裏記錄多個相關數字這種存儲區的類型叫結構體類型,這種類型需要首先創建出來然後才能使用
2 結構體類型存儲區裏包含多個子存儲區,每個子存儲區可以記錄一個數字,結構體中不同子存儲區的類型可以不同,子存儲區甚至也可以是結構體類型的存儲區
3 結構體聲明語句可以用來創建結構體類型,結構體聲明語句中需要使用struct關鍵字
4 結構體聲明語句中包含多個變量聲明語句,每個變量叫做結構體的成員變量,C語言中結構體不可以包含函數
5 成員變量聲明語句不會分配內存,它只是用來表示子存儲區的類型和名稱的,結構體聲明語句不分配內存所以可以寫在任何地方(包括頭文件裏)
6 結構體類型可以用來聲明變量,這種變量叫結構體變量,
7 把struct關鍵字和結構體名稱合起來作為類型名稱就可以聲明結構體變量了
8 可以使用typedef關鍵字給數據類型起別名,別名可以用來代替原來的類型名稱,可以把聲明結構體的語句和起別名的語句,合並成一條語句,這個時候可以省略結構體本身的名稱,但是以後就只能用別名聲明結構體變量了
9 結構體變量應該進行初始化,結構體變量初始化的格式和數組初始化的格式一樣
10 通常不會把結構體存儲區當作整體使用,一般一次只使用其中某個子存儲區,可以在結構體變量名稱後使用.然後再加上某個成員變量名稱,這個寫法可以表示某個子存儲區
11 同類型結構體變量之間可以直接賦值
12 結構體指針可以用來記錄結構體存儲區的地址,當一個結構體指針和一個結構體存儲區捆綁後就可以在指針後使用->然後再加上成員變量名稱來表示某個子存儲區
#include <stdio.h> /*struct person { int age; float height; char name[10]; }; typedef struct person sperson;*/ typedef struct /*person*/ { int age; float height; char name[10]; } sperson; int main() { //struct person prsn; //結構體變量聲明語句 sperson prsn1 = {20, 1.74f, "abc"}; sperson prsn2 = {0}; sperson *p_person = NULL; //結構體指針 printf("請輸入年齡:"); scanf("%d", &(prsn1.age)); printf("請輸入身高:"); scanf("%g", &(prsn1.height)); scanf("%*[^\n]"); scanf("%*c"); printf("請輸入姓名:"); fgets(prsn1.name, 10, stdin); printf("年齡是%d\n", prsn1.age); printf("身高是%g\n", prsn1.height); printf("姓名是%s\n", prsn1.name); prsn2 = prsn1; printf("年齡是%d\n", prsn2.age); printf("身高是%g\n", prsn2.height); printf("姓名是%s\n", prsn2.name); p_person = &prsn1; printf("年齡是%d\n", p_person->age); printf("身高是%g\n", p_person->height); printf("姓名是%s\n", p_person->name); return 0; }
#include <stdio.h> typedef struct { int row, col; } pt; typedef struct { pt pt1, pt2; } rect; int main() { rect r1 = {0}, *p_rect = NULL; pt mid = {0}, *p_mid = NULL; /*printf("請輸入水平長方形的位置:"); scanf("%d%d%d%d", &(r1.pt1.row), &(r1.pt1.col), &(r1.pt2.row), &(r1.pt2.col)); mid.row = (r1.pt1.row + r1.pt2.row) / 2; mid.col = (r1.pt1.col + r1.pt2.col) / 2; printf("中間點位置是(%d, %d)\n", mid.row, mid.col);*/ p_rect = &r1; p_mid = ∣ printf("請輸入水平長方形的位置:"); scanf("%d%d%d%d", &(p_rect->pt1.row), &(p_rect->pt1.col), &(p_rect->pt2.row), &(p_rect->pt2.col)); p_mid->row = (p_rect->pt1.row + p_rect->pt2.row) / 2; p_mid->col = (p_rect->pt1.col + p_rect->pt2.col) / 2; printf("中間點位置是(%d, %d)\n", p_mid->row, p_mid->col); return 0; }
13 結構體類型形式參數可以把結構體數據從調用函數傳遞給被調用函數,這種做法會導致時間和空間上的浪費,使用結構體指針形式參數可以避免這種浪費
#include <stdio.h> typedef struct { int row, col; } pt; pt *read(pt *p_pt) { pt pt1 = {0}; printf("請輸入點的位置:"); scanf("%d%d", &(p_pt->row), &(p_pt->col)); return p_pt; } void print(const pt *p_pt) { printf("點的位置是(%d, %d)\n", p_pt->row, p_pt->col); } int main() { pt pt1 = {0}, *p_pt = NULL; p_pt = read(&pt1); print(p_pt); return 0; }
14 聲明結構體指針形式參數的時候盡量使用const關鍵字
#include <stdio.h> typedef struct
{ int row, col; } pt; typedef struct
{ pt pt1, pt2; } rect; int area(const rect *p_rect)
{ int ret = (p_rect->pt1.row - p_rect->pt2.row) * (p_rect->pt1.col - p_rect->pt2.col); return ret >= 0 ? ret : 0 - ret; } int main()
{ rect r1 = {0}; printf("請輸入一個水平長方形的位置:"); scanf("%d%d%d%d", &(r1.pt1.row), &(r1.pt1.col), &(r1.pt2.row), &(r1.pt2.col)); printf("面積是%d\n", area(&r1)); return 0; }
15 可以把結構體變量作為返回值使用把結構體數據傳遞給調用函數,這樣也會造成時間和空間的浪費,把結構體存儲區的地址作為返回值可以避免這種浪費
#include <stdio.h> typedef struct { int row, col; } pt; typedef struct { pt center; int radius; } circle; circle *larger(const circle *p_cl1, const circle *p_cl2) { eturn (circle *)(p_cl1->radius > p_cl2->radius ? p_cl1 : p_cl2); } int main() { circle cl1 = {0}, cl2 = {0}, *p_circle = NULL; printf("請輸入一個圓的位置:"); scanf("%d%d%d", &(cl1.center.row), &(cl1.center.col), &(cl1.radius)); printf("請再次輸入一個圓的位置:"); scanf("%d%d%d", &(cl2.center.row), &(cl2.center.col), &(cl2.radius)); p_circle = larger(&cl1, &cl2); printf("結果是((%d, %d), %d)\n", p_circle->center.row, p_circle->center.col, p_circle->radius); return 0; }
16 不可以把局部結構體存儲區的地址作為返回值使用
17 一個存儲區的地址必須是它自身大小的整數倍(double類型存儲區的地址只需要是4的整數倍),這個規則叫數據對齊,結構體內部的子存儲區通常也需要遵守數據對齊的規則
數據對齊可能導致結構體不同子存儲區之間有空隙
18 結構體存儲區的大小必須是內部包含的最大基本類型子存儲區大小的整數倍(如果最大基本類型子存儲區的類型是double則結構體存儲區的大小只需要是4的整數倍)這個規則叫數據補齊,數據補齊可能造成結構體存儲區最後有浪費的字節
#include <stdio.h> typedef struct { char buf[2]; int num; } tmp; typedef struct { char ch; int num; char ch1; } tmp1; int main() { printf("sizeof(tmp)是%d\n", sizeof(tmp)); //8 printf("sizeof(tmp1)是%d\n", sizeof(tmp1)); //12 return 0; }
19 總結
#include <stdio.h> typedef struct { int row, col; } pt; typedef struct { pt center; int radius; } circle; int len2(const pt *p_pt1, const pt *p_pt2)
{ return (p_pt1->row - p_pt2->row) * (p_pt1->row - p_pt2->row) + (p_pt1->col - p_pt2->col) * (p_pt1->col - p_pt2->col); } int relation(const pt *p_pt, const circle *p_cl)
{ int tmp = len2(p_pt, &(p_cl->center)); if (tmp > p_cl->radius * p_cl->radius)
{ return 1; } else if (tmp < p_cl->radius * p_cl->radius)
{ return -1; } else
{ return 0; } } int main()
{ int tmp = 0; pt pt1 = {0}; circle cl = {0}; printf("請輸入一個點的位置:"); scanf("%d%d", &(pt1.row), &(pt1.col)); printf("請輸入一個圓的位置:"); scanf("%d%d%d", &(cl.center.row), &(cl.center.col), &(cl.radius)); tmp = relation(&pt1, &cl); if (tmp == 1) { printf("點在圓外\n"); } else if (!tmp) { printf("點在圓上\n"); } else { printf("點在圓內\n"); } return 0; }
結構體對齊