280 likes | 352 Views
Chapter 9. 結構 (Structure). 什麼是結構?. 目前的資料型態 (int, char, float, …) 夠用嗎? 陣列能代表同種型態的多個變數,但不同型態的多個變數怎麼宣告? 多個不同型態的陣列 在資料的整體性來說太過混亂 彼此間的關係互動,較容易疏忽 使用結構性的資料型態 有規則、架構,容易分析 容易控制,互動性較高. 結構範例 (1/2). 欲建立死黨通訊錄,應該要包括: 姓名(綽號)、地址、電話 … 陣列方式: 姓名陣列、地址陣列、電話陣列 … 難以對應,沒架構性 結構方式: 編號: 姓名、地址、電話 ….
E N D
Chapter 9 結構 (Structure)
什麼是結構? • 目前的資料型態(int, char, float, …)夠用嗎? • 陣列能代表同種型態的多個變數,但不同型態的多個變數怎麼宣告? • 多個不同型態的陣列 • 在資料的整體性來說太過混亂 • 彼此間的關係互動,較容易疏忽 • 使用結構性的資料型態 • 有規則、架構,容易分析 • 容易控制,互動性較高
結構範例 (1/2) • 欲建立死黨通訊錄,應該要包括: • 姓名(綽號)、地址、電話… • 陣列方式: • 姓名陣列、地址陣列、電話陣列… • 難以對應,沒架構性 • 結構方式: • 編號: • 姓名、地址、電話…
結構範例 (2/2) • 陣列方式 • 結構方式 仁齋XXX室 火車站旁 胖子 老外 03-5715131 28825252 國宅 大頭 0204123456
結構的定義 (1/2) • struct 結構名稱 {資料型態 結構元素1;資料型態 結構元素2; .......資料型態 結構元素n; }; • Ex: • struct addrbook{ char name[20]; char addr[60]; int phone[20];};
結構的定義 (2/2) • 宣告的變數種類與數目並不設限。 • 宣告結構型態,並不佔用記憶體,只有宣告。要使用他,必須宣告一個這種型態的變數來用。 • 一樣有變數範圍(scope)的限制,在哪個位置宣告的,就有相對應的有效範圍。 • 結構之中之變數型態亦可使用結構型態,仍可包含自己或其他以定義之結構。 • 結構的大小取決於所有組成的元素。
結構型態變數的宣告 • 直接在定義時宣告 • struct 結構名稱 {資料型態 結構元素1;資料型態 結構元素2; .......資料型態 結構元素n; } xxx, a[30], *ptr; • 以struct為型態宣告 • 在宣告前該 struct 必須定義過,定義在程式的開頭 • struct 結構名稱 xxx, a[30], *ptr;
結構的使用 • 結構成員之使用方式:經由位址或名稱 • 位址: • ->: (結構之位址)->成員 • ptr->name • (&a)->name • &a一定要括號,因為運算優先權 ->比 &高 • 名稱: • .:(結構名稱).成員 • a.name • (*ptr).name • *ptr一定要括號,因為運算優先權 .比 * 高
結構範例 (1/2) #include <stdio.h> #include <string.h> struct addrbook{ //定義addrbook型態變數 char name[20]; char addr[60]; char phone[20]; }; int main(void) { struct addrbook a; //宣告一個addrbook型態的變數 struct addrbook *ptr; //宣告一個addrbook型態的指標 strcpy(a.name, "clsu"); strcpy(a.addr, "EECS Building 820R"); strcpy(a.phone, "4158"); ptr = &a; //將addrbook型態的指標指到同型態的變數 a
結構範例 (2/2) printf("sizeof(a): %d, sizeof(&a): %d\n", sizeof(a), sizeof(&a)); printf("sizeof(ptr): %d, sizeof(*ptr): %d\n", sizeof(ptr), sizeof(*ptr)); printf("a.name: %d, a.addr: %d, a.phone: %d\n", sizeof(a.name), sizeof(a.addr), sizeof(a.phone)); printf("a.: %s, %s, %s\n", a.name, a.addr, a.phone); printf("(&a)->: %s, %s, %s\n", (&a)->name, (&a)->addr, (&a)->phone); printf("ptr->: %s, %s, %s\n", ptr->name, ptr->addr, ptr->phone); printf("(*ptr).: %s, %s, %s\n", (*ptr).name, (*ptr).addr, (*ptr).phone); return 0; } sizeof(a): 100, sizeof(&a): 4 sizeof(ptr): 4, sizeof(*ptr): 100 a.name: 20, a.addr: 60, a.phone: 20 a.: clsu, EECS Building 820R, 4158 (&a)->: clsu, EECS Building 820R, 4158 ptr->: clsu, EECS Building 820R, 4158 (*ptr).: clsu, EECS Building 820R, 4158
在結構中使用其他結構 • 結構是一種資料型態的定義,用來表示多樣的資料 • 他的成員可以包括其他資料型態,當然也可包括已定義的結構(包含自己本身) • 如果於結構中某一筆資料又可分成其他細項,這樣可用另一結構來表示 • 若結構成員中所表示的是一個與自己相同結構,則可寫成自己本身,例如:鏈結串列(linked list)
結構中有結構之範例 (1/3) #include <stdio.h> #include <string.h> struct address{ //定義address的結構 int town; int road; int num; }; struct addrbook{ //定義addrbook的結構 char name[20]; struct address addr; //addr本身是另一結構 char phone[20]; }; int main(void) { struct addrbook a; struct addrbook *ptr;
結構中有結構之範例 (2/3) strcpy(a.name, "clsu"); a.addr.town = 1; //定義addr的內容 a.addr.road = 3; //兩層結構 a.addr.num = 36; strcpy(a.phone, "4158"); ptr = &a; printf("sizeof(a): %d, sizeof(&a): %d\n", sizeof(a), sizeof(&a)); printf("sizeof(ptr): %d, sizeof(*ptr): %d\n", sizeof(ptr), sizeof(*ptr)); printf("a.name: %d, a.addr: %d, a.phone: %d\n", sizeof(a.name), sizeof(a.addr), sizeof(a.phone)); printf("a.: %s, town:%2d road:%2d num:%2d, %s\n", a.name, a.addr.town, a.addr.road, a.addr.num, a.phone); printf("(&a)->: %s, town:%2d road:%2d num:%2d, %s\n", (&a)->name, (&a)->addr.town, (&a)->addr.road, (&a)->addr.num, (&a)->phone); name addr town phone road num
結構中有結構之範例 (3/3) printf("ptr->: %s, town:%2d road:%2d num:%2d, %s\n", ptr->name, (&ptr->addr)->town, (&ptr->addr)->road, (&ptr->addr)->num, ptr->phone); printf("(*ptr).: %s, town:%2d road:%2d num:%2d, %s\n", (*ptr).name, (*ptr).addr.town, (*ptr).addr.road, (*ptr).addr.num, (*ptr).phone); return 0; } 執行結果: sizeof(a): 52, sizeof(&a): 4 sizeof(ptr): 4, sizeof(*ptr): 52 a.name: 20, a.addr: 12, a.phone: 20 a.: clsu, town: 1 road: 3 num:36, 4158 (&a)->: clsu, town: 1 road: 3 num:36, 4158 ptr->: clsu, town: 1 road: 3 num:36, 4158 (*ptr).: clsu, town: 1 road: 3 num:36, 4158
結構與函式 • 結構亦是一種變數,所以也可以在函數間傳遞 • 呼叫者與被呼叫之函式的型態要一致 • struct 對應 struct • struct 成員對應該成員的資料型態 • struct 的指標 對應 struct 的指標
結構傳遞範例 (1/3) #include <stdio.h> #include <string.h> struct address{ int town; int road; int num; }; struct addrbook{ char name[20]; struct address addr; char phone[20]; }; void dump(struct addrbook a){ //以addrbook型態之變數接收 struct addrbook *ptr; //宣告addrbook型態之指標 ptr = &a; //將宣告之指標指到接收到的 a printf("sizeof(a): %d, sizeof(&a): %d\n", sizeof(a), sizeof(&a));
結構傳遞範例 (2/3) printf("sizeof(ptr): %d, sizeof(*ptr): %d\n", sizeof(ptr), sizeof(*ptr)); printf("a.name: %d, a.addr: %d, a.phone: %d\n", sizeof(a.name), sizeof(a.addr), sizeof(a.phone)); printf("a.: %s, town:%2d road:%2d num:%2d, %s\n", a.name, a.addr.town, a.addr.road, a.addr.num, a.phone); printf("ptr->: %s, town:%2d road:%2d num:%2d, %s\n", ptr->name, (&ptr->addr)->town, (&ptr->addr)->road, (&ptr->addr)->num, ptr->phone); } int main(void) { struct addrbook a; strcpy(a.name, "clsu"); a.addr.town = 1; a.addr.road = 3;
結構傳遞範例 (3/3) a.addr.num = 36; strcpy(a.phone, "4158"); dump(a); //傳遞addrbook型態之變數 return 0; } 執行結果: sizeof(a): 52, sizeof(&a): 4 sizeof(ptr): 4, sizeof(*ptr): 52 a.name: 20, a.addr: 12, a.phone: 20 a.: clsu, town: 1 road: 3 num:36, 4158 ptr->: clsu, town: 1 road: 3 num:36, 4158
結構指標傳遞範例 (1/3) #include <stdio.h> #include <string.h> struct address{ int town; int road; int num; }; struct addrbook{ char name[20]; struct address addr; char phone[20]; }; void dump(struct addrbook *ptr){ //用addrbook型態的指標接收 struct addrbook a; //宣告一個addrbook型態的變數 a = *ptr; printf("sizeof(a): %d, sizeof(&a): %d\n", sizeof(a), sizeof(&a));
結構指標傳遞範例 (2/3) printf("sizeof(ptr): %d, sizeof(*ptr): %d\n", sizeof(ptr), sizeof(*ptr)); printf("a.name: %d, a.addr: %d, a.phone: %d\n", sizeof(a.name), sizeof(a.addr), sizeof(a.phone)); printf("a.: %s, town:%2d road:%2d num:%2d, %s\n", a.name, a.addr.town, a.addr.road, a.addr.num, a.phone); printf("ptr->: %s, town:%2d road:%2d num:%2d, %s\n", ptr->name, (&ptr->addr)->town, (&ptr->addr)->road, (&ptr->addr)->num, ptr->phone); } int main(void) { struct addrbook a; struct addrbook *ptr; ptr = &a; strcpy(a.name, "clsu");
結構指標傳遞範例 (3/3) a.addr.town = 1; a.addr.road = 3; a.addr.num = 36; strcpy(a.phone, "4158"); dump(ptr); //傳遞addrbook型態的指標 return 0; } 執行結果: sizeof(a): 52, sizeof(&a): 4 sizeof(ptr): 4, sizeof(*ptr): 52 a.name: 20, a.addr: 12, a.phone: 20 a.: clsu, town: 1 road: 3 num:36, 4158 ptr->: clsu, town: 1 road: 3 num:36, 4158
指標跟回傳值 (1/3) #include <stdio.h> // 回傳值跟指標的關係,三種不同的回傳方式 struct PHONE{ //定義PHONE char country[5]; char region[5]; char tel[20]; char ext[6]; }; typedef struct ADDRBK{ //定義 ADDRBK char name[20]; struct PHONE tel; //tel 是結構 int age; } *ADDRBKPTR; //typedef struct ADDRBK *ADDRBKPTR; struct ADDRBK modify1(struct ADDRBK entry) { entry.age ++; return entry; }
指標跟回傳值 (2/3) int modify2(struct ADDRBK entry) { entry.age ++; return entry.age; } void modify3(ADDRBKPTR ptr) { ptr->age++; } int main(void) { struct ADDRBK person = {"clsu", {"886","3","5715131","4128"},27}; printf("%s %s-%s-%s-%s %d\n", person.name, person.tel.country, person.tel.region, person.tel.tel, person.tel.ext, person.age); person = modify1(person); //接受一整個結構 printf("%s %s-%s-%s-%s %d\n", person.name, person.tel.country, person.tel.region, person.tel.tel, person.tel.ext, person.age); person.age = modify2(person); //只回傳修改的成員
指標跟回傳值 (3/3) printf("%s %s-%s-%s-%s %d\n", person.name, person.tel.country, person.tel.region, person.tel.tel, person.tel.ext, person.age); modify3(&person); //模擬 call by reference printf("%s %s-%s-%s-%s %d\n", person.name, person.tel.country, person.tel.region, person.tel.tel, person.tel.ext, person.age); return 0; } 執行結果: clsu 886-3-5715131-4128 27 clsu 886-3-5715131-4128 28 clsu 886-3-5715131-4128 29 clsu 886-3-5715131-4128 30
暱稱 (typedef) • 人有暱稱,C語言中也可以取暱稱 • 胖子、大頭、老外 … • 每次使用 struct 宣告太長,不人性,我們可以使用typedef 幫他取暱稱 • typedef struct 結構名稱 暱稱; • typedef struct{…} 暱稱; • 宣告時只需寫暱稱即可 • 暱稱 xxx, a[30], *ptr;
typedef的範例 (1/3) #include <stdio.h> #include <string.h> struct address{ int town; int road; int num; }; typedef struct{ char name[20]; struct address addr; char phone[20]; } Add; //幫addrbook取暱稱 void dump(Add *ptr){ //用暱稱來接收 Add a; //用暱稱來宣告 a = *ptr; printf("sizeof(a): %d, sizeof(&a): %d\n", sizeof(a), sizeof(&a));
typedef的範例 (2/3) printf("sizeof(ptr): %d, sizeof(*ptr): %d\n", sizeof(ptr), sizeof(*ptr)); printf("a.name: %d, a.addr: %d, a.phone: %d\n", sizeof(a.name), sizeof(a.addr), sizeof(a.phone)); printf("a.: %s, twon:%2d road:%2d num:%2d, %s\n", a.name, a.addr.town, a.addr.road, a.addr.num, a.phone); printf("ptr->: %s, twon:%2d road:%2d num:%2d, %s\n", ptr->name, (&ptr->addr)->town, (&ptr->addr)->road, (&ptr->addr)->num, ptr->phone); } int main(void) { Add a; //用暱稱宣告addrbook型態的變數 Add *ptr; //用暱稱宣告addrbook型態的指標 ptr = &a; strcpy(a.name, "clsu");
typedef的範例 (3/3) a.addr.town = 1; a.addr.road = 3; a.addr.num = 36; strcpy(a.phone, "4158"); dump(ptr); //傳遞addrbook型態的指標 return 0; } 執行結果: sizeof(a): 52, sizeof(&a): 4 sizeof(ptr): 4, sizeof(*ptr): 52 a.name: 20, a.addr: 12, a.phone: 20 a.: clsu, twon: 1 road: 3 num:36, 4158 ptr->: clsu, twon: 1 road: 3 num:36, 4158