struct 可以在同一個名稱下擁有多種資料型態。使用struct能讓資料的存取和處理更為靈活。

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

C语言程序设计 主讲教师 :张群燕 电话:
第 2 章 初探 C++.
程序设计实习 3月份练习解答
第一章 C语言概述 计算机公共教学部.
第三章 鏈結串列 Linked List.
第九讲 类与对象 (I)面向对象基础.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
第八章 类和对象.
單向鏈結串列 Singly Linked Lists.
程式設計 博碩文化出版發行.
走向C++之路 WindyWinter WindyWinter感谢诸位前来捧场。
資料大樓 --談指標與陣列 綠園.
佇列 (Queue).
Chap 18 類別與物件 夫有土者,有大物也。有大物者,不可以物。 物而不物,故能物物。 明乎物物者之非物也,豈獨治天下百姓而已哉!
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
C++程序设计 第二讲 清华大学软件学院.
Scope & Lifetime 前言 Local Scope Global Functions & Objects
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
第三章 C++中的C 面向对象程序设计(C++).
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
第3讲 C++程序控制结构 3.1 顺序结构 3.2 分支结构 3.3 循环结构 3.4 转向控制 3.5 综合案例分析.
C++程序设计 string(字符串类) vector(容器类).
五、链 表 1、单链表 2、双向链表 3、链表应用.
C++语言程序设计 第二章 C++简单程序设计.
程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句
C++语言程序设计 第十一章 流类库与输入/输出.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
樹 2 Michael Tsai 2013/3/26.
第三章 链表 单链表 (Singly Linked List) 循环链表 (Circular List) 多项式及其相加
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
自我參考結構 (self-reference – 1)
第三章 链表 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵.
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
OOP6 結構Struct 黃兆武.
Name1..hour //加班時數 name2..hour //請假時數
第二章 基本数据类型及运算 C数据类型概述 基本数据类型 运算符和表达式 混合运算与类型转换 数据的输入输出 顺序程序设计举例.
Chapter 2 & Chapter 3.
程式結構&語法.
Speaker: Liu Yu-Jiun Date: 2009/4/29
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
物件導向程式設計 CH2.
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
C++程式設計入門 變數與運算子 作者:黃建庭.
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第 3 章 类的基础部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
C++语言程序设计 第十章 C++标准模板库 成都信息工程学院计算机系.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
本章主題 C++的程式結構 資料型態與宣告 算術運算 簡易的輸入輸出指令 程式編譯(Compile)的過程與原理.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
變數與資料型態  綠園.
資料!你家住哪裏? --談指標 綠園.
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

struct 可以在同一個名稱下擁有多種資料型態。使用struct能讓資料的存取和處理更為靈活。 Chap 15 struct與資料結構 struct 可以在同一個名稱下擁有多種資料型態。使用struct能讓資料的存取和處理更為靈活。

struct與資料結構 15.1 struct的宣告和使用 15.2 由struct構成的陣列 15.3 struct資料型態與函數參數的傳遞 15.4 struct實例的動態宣告 15.5 指標成員與資料結構 15.6 union資料型態 15.7 enum資料型態

struct的宣告和使用 組成份子稱為成員 (member) 或資料欄位 (data field)。 成員可以是各種不同的資料型態 (複合式資料型態)。 關鍵字struct是英文 structure (結構) 的縮寫,此種資料結構又稱為記錄(record)。

struct資料型態的宣告範例 Employee包括的資料成員有Name (姓名)、Phone (電話號碼) 以及Id (編號) 三種: { char Name[20]; char Phone[10]; int Id; }; // 注意這要用到「;」!

Struct 在記憶體中的儲存方式 各成員的儲存位置是連續的:

定義了兩個名稱分別為Ea和Eb的Employee變數。 由某一資料型態定義的變數稱為該資料型態的實例 (instance)。 使用struct 資料型態定義變數 可以使用標準的定義敘述。例如: Employee Ea, Eb; 定義了兩個名稱分別為Ea和Eb的Employee變數。 由某一資料型態定義的變數稱為該資料型態的實例 (instance)。

定義變數時一併給予初始值 例如,上面的敘述可進一步寫成: Employee Ea = {"Ann", "02384125", 105}; Employee Eb = {"Joanne", "03544132", 106};

要存取Employee變數的個別資料欄位 必需同時給定變數名稱和資料成員名稱,中間用一個成員運算符號 (member operator)「.」隔開。例如: Ea.Name // 其值目前分別為 “Ann” Eb.Phone // 其值目前分別為“02384125” Ea.Id // 其值目前分別為105 分別用來代表Ea這個Employee變數的三個成員,其值目前分別為“Ann”,“02384125”和105。這個語法基本上和我們在10.1節介紹的成員函數的語法是一致的。

範例程式TestStruct.cpp 如何使用struct宣告自訂的資料型態,以及各欄位內的資料如何存取。

範例程式 檔案 TestStruct.cpp // TestStruct.cpp #include <iostream> using namespace std; struct Employee { char Name[20]; char Phone[10]; int Id; }; // ----- 主程式 ----------------------------

int main() { EmployeeEa= {"Ann", "02384125", 105}; Employee Eb = {"Joanne", "03544132", 106}; cout << "Ea 的資料是:\n" << "姓名 : " << Ea.Name << '\n' << "電話號碼: " << Ea.Phone << '\n' << "編號 : " << Ea.Id << endl; cout << "Eb 的資料是:\n" << "姓名 : " << Eb.Name << '\n' << "電話號碼: " << Eb.Phone << '\n' << "編號 : " << Eb.Id << endl; return 0; }

執行結果 Ea 的資料是: 姓名 : Ann 電話號碼: 02384125 編號 : 105 Eb 的資料是: 姓名 : Joanne 編號 : 105 Eb 的資料是: 姓名 : Joanne 電話號碼: 03544132 編號 : 106

合併struct資料型態的宣告和變數的定義 例如: struct { char Name[20]; char Phone[10]; int Id; } Ea, Eb; 由於粗體字的部份本身就是已經是新定義的資料型態之具體內容,不用再取個名稱來代表它。

比較資料型態變數的語法

由struct構成的陣列 Employee Officer[50]; 結合陣列和struct,可以一次完成很多具有相同結構的struct變數的定義。 例如,可以使用 Employee Officer[50]; 同時定義從Officer[0] 到Officer[49],共50個Employee變數

struct陣列各欄位的資料 cout << Officer[8].Name << endl; cout << Officer[12].Phone << endl; cout << Officer[40].Id << endl;

範例程式StructArray.cpp 允許使用者逐一輸入各陣列元素的各成員值 (每輸入一個項目後,要按兩次Enter鍵)。

範例程式 檔案 StructArray.cpp #include <iostream> using namespace std; const int NameSize = 20; const int PhoneSize = 10; struct Employee { char Name[NameSize]; char Phone[PhoneSize]; }; int main() const int Size = 2; Employee Officer[Size]; cout << "共 " << Size << " 個 Officers:\n";

for (int i=0; i<Size; i++) { cout << "請輸入 Officer[" << I << "] 的姓名: "; cin.getline(Officer[i].Name, NameSize, '\n'); cout << "電話號碼: "; cin.getline(Officer[i].Phone, PhoneSize, '\n'); } cout << "Officer[" << i << "] 的資料是:\n" << "姓名 : " << Officer[i].Name << '\n' << "電話號碼: " << Officer[i].Phone << '\n'; return 0;

執行結果 共2個Officers: 請輸入Officer[0] 的姓名: Alan John 電話號碼: 03-4521234 請輸入 Officer[1] 的姓名: Peter Pan 電話號碼: 02-4354512 Officer[0] 的資料是: 姓名 : Alan John 電話號碼: 03-4521234 Officer[1] 的資料是: 姓名 : Peter Pan

struct資料型態與函數參數的傳遞 由struct所定義的實例被用來做為參數傳遞時,其預設的語意是傳值 (pass-by-value)。 也就是說,在「被呼叫函數」內部將另外產生一個複製資料,而不會影響「呼叫函數」內的資料。

用struct所定義的實例來傳遞參數 例如,呼叫敘述可以寫成: 而被呼叫函數則可以定義成: ShowMember(Ea); 而被呼叫函數則可以定義成: void ShowMember(Employee A) { cout << "資料的詳細內容是:\n" << "姓名 : " << A.Name << '\n' << "電話號碼: " << A.Phone << '\n' << "編號 : " << A.Id << endl; return; }

使用傳參照 (pass by reference) 改變struct實例的內容 例如: ChangeName(Ea, “Jackson”); 對應的「被呼叫函數」則定義成: void ChangeName (Employee& A, char NewName[]) { strcpy(A.Name, NewName); return; }

範例程式 檔案 StructFnc.cpp // StructFnc.cpp #include <iostream> using namespace std; struct Employee { char Name[20]; char Phone[10]; int Id; }; void ShowMember(Employee A) cout << "資料的詳細內容是:\n" << "姓名 : " << A.Name << '\n' << "電話號碼: " << A.Phone << '\n' << "編號 : " << A.Id << endl; return; }

void ChangeName (Employee& A, char NewName[]) { strcpy(A.Name, NewName); return; } // ============= 主程式 ======================== int main() { Employee Ea = {"Ann", "02384125", 105}; Employee Eb = {"Joanne", "03544132", 106}; ShowMember(Ea); ShowMember(Eb); ChangeName(Ea, "Jackson"); cout << "執行 ChangeName() 後:\n"; return 0; }

執行結果 資料的詳細內容是: 姓名 : Ann 電話號碼: 02384125 編號 : 105 姓名 : Joanne 編號 : 105 姓名 : Joanne 電話號碼: 03544132 編號 : 106 執行 ChangeName() 後: 姓名 : Jackson

使用指標改變struct實例的內容 使用傳址 (pass-by-address) 來達到使用參照的目的: 「被呼叫函數」則定義為 ChangeId(&Ea, 00128); 「被呼叫函數」則定義為 void ChangeId(Employee* pE, int NewId) { (*pE).Id=NewId; return; }

pE與Ea之間的關係

C++ 的具象指標符號 -> 將 (*pE).Name寫成: pE->Name 表示「由pE指向的struct變數內的成員 Name」。

進一步改寫 ChangeId() void ChangeId(Employee* pE, int NewId) { pE->Id = NewId; return; }

範例程式 檔案 StructFnc2.cpp // StructFnc2.cpp #include <iostream> using namespace std; struct Employee { char Name[20]; char Phone[10]; int Id; }; void ShowMember(Employee A) cout << "資料的詳細內容是:\n" << "姓名 : " << A.Name << '\n' << "電話號碼: " << A.Phone << '\n' << "編號 : " << A.Id << endl; return; }

void ChangeName (Employee& A, char NewName[]) { strcpy(A.Name, NewName); return; } void ChangeId(Employee* pE, int NewId) { pE->Id = NewId; return;} // ========= 主程式 ======================== int main() { Employee Ea = {"Ann", "02384125", 105}; Employee Eb = {"Joanne", "03544132", 106}; ShowMember(Ea); ShowMember(Eb); ChangeId(&Ea, 208); cout << "執行 ChangeId() 後:\n"; return 0; }

執行結果 資料的詳細內容是: 姓名 : Ann 電話號碼: 02384125 編號 : 105 姓名 : Joanne 編號 : 105 姓名 : Joanne 電話號碼: 03544132 編號 : 106 執行 ChangeId() 後: 編號 : 208

亦即struct實例的動態記憶體配置(dynamic memory allocation)。 下列敘述則可以在執行時才臨時決定陣列的大小: int Size; cin >> Size; Employee* pE = new Employee[Size];

struct實例的動態記憶體配置和回收 執行後會依指定的大小在記憶體的特殊區域,稱為記憶堆 (heap) 的地方,規劃出需要的記憶空間,並把第一個變數的開頭位址存入指標內。 如果此陣列不再需要,可以執行下列的敘述回收記憶體空間: delete [] pE;

例如,要取用第k個陣列元素內的成員Id,下述語法都是正確的: 使用陣列下標或指標算數存取內部成員 例如,要取用第k個陣列元素內的成員Id,下述語法都是正確的: Labor[k].Id (*(Labor + k)).Id (Labor + k)->Id pE[k].Id (*(pE + k)).Id (pE + k)->Id

範例程式DynStruct.cpp 示範動態產生由struct實例所構成的陣列,稱為Employee,之完整語法,並在事後回收記憶空間。

範例程式 檔案 DynStruct.cpp // DynStruct.cpp #include <iostream> using std::cin; using std::cout; struct Employee { char Name[20]; char Phone[10]; int Id; }; // --------- 主程式 ------------------------

int main() { int Size; cout << "請輸入 Employee 的數目:\n"; cin >> Size; Employee* pE = new Employee[Size]; delete [] pE; return 0; }

指標成員與資料結構 struct所宣告的資料型態可以使用「指標」做為成員。 指標成員可以指向自己所在的struct資料型態,稱為「自我參照」(auto-reference)。例如: Struct Data { int Id; Data* pD; };

串列 (lists) 定義一串的Data變數: 圖示如下: Data D1, D2, D3; D1.pD = &D2; D2.pD = &D3; 圖示如下: 串列最後一個元素內的指標值為NULL (亦即 ‘\0’),用來做為檢查串列是否「到此為止」的根據。

串列 (lists) 「節點」(node): 每一個用來儲存資料的元素第一個節點稱為 「開頭」(head): 第一個節點。 「結尾」(tail): 最後的節點。

在陣列插入一個元素 必需同時將V[1] 及其之後的所有元素往右移,且無法應付陣列因長度增加而記憶空間可能不足的問題。 int* V = new int [Size]; 必需同時將V[1] 及其之後的所有元素往右移,且無法應付陣列因長度增加而記憶空間可能不足的問題。

「串列」可以帶來的便利 使用串列 (linked list) 可以較有效率地完成元素增刪的動作。 設想原先有A, B, C 三個元素串接在一起形成一個串列:

假設使用struct宣告了一個名叫 Element 的自訂資料形態: 一個串列的範例 假設使用struct宣告了一個名叫 Element 的自訂資料形態: struct Element { int Value; Element* Next; };

動態產生任意數目的Element (各實例的值在此為0, 2, 4, 6, …): cout << "請輸入 Element 的數目:\n"; cin >> Size; Element* pE = new Element[Size]; for (int i=0; i<(Size-1); i++) pE[i].Next = pE + i +1; pE[Size-1].Next = NULL; for (int i=0; i<(Size); i++) pE[i].Value = i*2;

顯示現有串列元素 不斷更換指標使它指向下一個元素的位址。 Element* pShow; for (pShow = pE; pShow != NULL; pShow=pShow->Next) cout << pShow->Value << ' '; 不斷更換指標使它指向下一個元素的位址。

以while迴圈顯示現有串列元素 Element* pShow=pE; while (pShow != NULL) { cout << pShow->Value << ' '; pShow = pShow->Next; }

將顯示串列內容的功能封裝到函數中 void ShowElement(Element* pShow) { while (pShow != NULL) cout << pShow->Value << ' '; pShow = pShow->Next; }

範例程式 檔案 ListStruct.cpp // ListStruct.cpp #include <iostream> using namespace std; struct Element { int Value; Element* Next; }; void ShowElement(Element* pShow) while (pShow != NULL) cout << pShow->Value << ' '; pShow = pShow->Next; }

// ---主程式------------------------ int main() { int Size; cout << "請輸入 Element 的數目:\n"; cin >> Size; Element* pE = new Element[Size]; for (int i=0; i<(Size-1); i++) pE[i].Next = pE + i +1; pE[Size-1].Next = NULL; for (int i=0; i<(Size); i++) pE[i].Value = i*2; cout << "Element 的內容是:\n"; ShowElement(pE); delete [] pE; return 0; }

執行結果 請輸入Element的數目: 5 Element的內容是: 0 2 4 6 8

雙向鏈結串列 (doubly- linked list) 能夠自由在串列中往返尋找。 每個節點內都含有兩個指標,分別指向下一個節點及上一個節點。

「雙向鏈結串列」的宣告 struct Node { int Value; Node* Previous; Node* Next; };

樹狀結構 (tree) 二維結構。 開頭的節點稱為「根」(root)。 「層」(layer): 與根的距離相同的所有節點。 「葉」(leaves): 不再指向下一層節點的所有節點。

二元樹 (binary tree) 由於每個節點都只有兩個指標向下一層的兩個節點,形成一個「品」字型的局部結構,因此稱為「二元樹」。

union資料型態 可以在其內擁有多種資料型態,但一次只能有一種資料型態。例如: union Data { float FloatValue; double DoubleValue; char CharValue; int IntValue; }; Data D1; 每個Data變數擁有的記憶空間由佔有最大空間的成員 (此例為D1.DoubleValue) 所決定。使用union的目的在於節省記憶體。

enum資料型態 enum是enumerate (列舉) 的簡寫。 由enum所定義的任何實例 (instance) 只能擁有當初enum宣告時所列舉的值之一。例如: enum Direction {Up, Down, Left, Right}; Direction x; 我們只能把這四種可能的值指定給x。例如: x = Right; 在電腦內部 {Up, Down, Left, Right} 分別和 {0, 1, 2, 3} 比對。

可以在宣告enum 時給予各成員確定的數值 例如: enum Check {Error = -1, Suspicious, Acceptable = 5, OK = 10}; 沒有特別指定的的值為其前一個成員 (亦即Error) 的值加1, 因此suspicious的內值為 –1 + 1 = 0。

enum資料型態 使用enum型態的目的是為了增進程式的可讀性,常與switch和if等判斷式結合使用。例如: int N; cin >> N; switch (N) { case Up: cout << “Moving Up!\n”; break; case Down: cout << “Moving Down!\n”; case Left: cout << “Moving Left!\n”;

case Right: cout << “Moving Right!\n”; break; default: cout << “Static\n”; }

範例程式 檔案 TestEnum.cpp case Up: cout << "Moving Up!\n"; break; #include <iostream> using namespace std; enum Direction {Up, Down, Left, Right}; // -------- 主程式 ------------------------ int main() { int N; cout << "請輸入期望的運動方向\n"; cout << "(0=Up, 1=Down, 2=Left, 3=Right):\n"; cin >> N; switch (N) case Up: cout << "Moving Up!\n"; break;

case Down: cout << "Moving Down!\n"; break; case Left: cout << "Moving Left!\n"; case Right: cout << "Moving Right!\n"; default: cout << "Static\n"; } return 0;

執行結果 請輸入期望的運動方向 (0=Up, 1=Down, 2=Left, 3=Right): 2 Moving Left!