13.2 定義結構體
定義的語法:關鍵字 struct、你取的型態名稱、大括號裡列出成員、結尾一個分號:
struct student { // 定義一個叫 student 的新型態
string name; // 成員變數:姓名
int seat; // 成員變數:座號
string phone; // 成員變數:電話
}; // 結尾的分號千萬別忘!
這五行就「發明」了一個新型態 student。大括號裡宣告的變數叫這個結構體的成員變數(member variables);成員的型態不限——int、string、陣列、vector,甚至另一個結構體都可以。定義通常放在 main 外面(跟全域變數同一個位置),讓整份程式都看得到它。型態名稱自己取,規則跟變數命名相同;有人習慣首字母大寫(提醒自己「這是型態、不是變數」),小寫也完全可以——本單元兩種都會示範。
¶宣告變數、用「.」存取成員
定義好之後,student 就是一個型態名稱,宣告變數的寫法跟 int a; 一模一樣;存取成員用句點 .——a.name 就是「a 的 name」:
#include <iostream>
#include <string>
using namespace std;
struct student {
string name;
int seat;
string phone;
};
int main() {
student a; // 宣告一個 student 型態的變數
a.name = "temmie"; // 用「.」存取成員:a 的 name
a.seat = 60;
a.phone = "0912345678";
cout << a.name << ' ' << a.seat << ' ' << a.phone << '\n';
return 0;
}
執行結果:
temmie 60 0912345678
a.name 就是一個普通的 string、a.seat 就是一個普通的 int——所有你會的操作(運算、比較、當參數傳)它們都照常支援。句點就是「的」,這個直覺你其實早就有了:p.first(10.11)、v.size()(10.2)都是同一個句點。
¶結構體陣列與整包賦值
student 既然是型態,開陣列天經地義:student a[35]; 就是 35 位同學,a[i] 是完整的一包,a[i].name 是第 i 包裡的姓名。讀入要逐成員寫——整包 cin >> a[i] 是編譯錯誤,因為沒人教過 cin 一個 student 長什麼樣:
#include <iostream>
#include <string>
using namespace std;
struct student {
string name;
int seat;
string phone;
};
student a[35]; // 結構體陣列:35 個 student,每一格都是完整的一包
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i].name >> a[i].seat >> a[i].phone; // a[i] 是一個 student
}
student b = a[0]; // 整包賦值:三個成員一次全部複製
b.seat = 99; // 動的是複本,a[0] 不受影響
cout << a[0].name << ' ' << a[0].seat << '\n';
cout << b.name << ' ' << b.seat << '\n';
return 0;
}
執行結果(輸入 2、alice 5 0911111111、bob 7 0922222222):
alice 5
alice 99
注意 student b = a[0]; 這行:結構體可以用 = 整包賦值。上冊的陣列不行(8.8 提過 t = s 是編譯錯誤)、vector 可以(10.6)——結構體站在 vector 這邊。而且就算成員裡包著一個陣列,賦值時陣列的內容也會整包照搬,這是結構體幫陣列「開的後門」。
動手試試看:自己定義一個「書」的結構體(書名 string、頁數 int、價格 int),宣告陣列、讀入 3 本書的資料再逐本印出——把定義、宣告、句點、陣列一次走過。