Wiki
結構體與共用體
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.結構體
1.1.結構體基本概念
結構體屬於使用者==自定義的資料型別==,允許使用者儲存不同的資料型別
1.2.結構體定義和使用
語法:struct 结构体名 { 结构体成员列表 };
通過結構體建立變數的方式有三種:
- struct 結構體名 變數名
- struct 結構體名 變數名 = { 成員1值 , 成員2值...}
- 定義結構體時順便建立變數
示例:
//结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
}stu3; //结构体变量创建方式3
int main() {
//结构体变量创建方式1
struct student stu1; //struct 关键字可以省略
stu1.name = "张三";
stu1.age = 18;
stu1.score = 100;
cout << "姓名:" << stu1.name << " 年龄:" << stu1.age << " 分数:" << stu1.score << endl;
//结构体变量创建方式2
struct student stu2 = { "李四",19,60 };
cout << "姓名:" << stu2.name << " 年龄:" << stu2.age << " 分数:" << stu2.score << endl;
stu3.name = "王五";
stu3.age = 18;
stu3.score = 80;
cout << "姓名:" << stu3.name << " 年龄:" << stu3.age << " 分数:" << stu3.score << endl;
return 0;
}
執行結果:
姓名:张三 年龄:18 分数:100
姓名:李四 年龄:19 分数:60
姓名:王五 年龄:18 分数:80
總結1:定義結構體時的關鍵字是struct,不可省略
總結2:建立結構體變數時,關鍵字struct可以省略
總結3:結構體變數利用運算子 ''.'' 訪問成員
1.3.結構體陣列
**作用:**將自定義的結構體放入到陣列中方便維護
語法: struct 结构体名 数组名[元素个数] = { {} , {} , ... {} }
示例:
//结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
}
int main() {
//结构体数组
struct student arr[3]=
{
{"张三",18,80 },
{"李四",19,60 },
{"王五",20,70 }
};
for (int i = 0; i < 3; i++)
{
cout << "姓名:" << arr[i].name << " 年龄:" << arr[i].age << " 分数:" << arr[i].score << endl;
}
return 0;
}
執行結果: 編譯失敗:結構體定義末尾缺少分號 ;,程式不會生成執行檔。
1.4.結構體指標
**作用:**通過指標訪問結構體中的成員
- 利用運算子
->可以通過結構體指標訪問結構體屬性
示例:
//结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
int main() {
struct student stu = { "张三",18,100, };
struct student * p = &stu;
p->score = 80; //指针通过 -> 操作符可以访问成员
cout << "姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl;
return 0;
}
執行結果:
姓名:张三 年龄:18 分数:80
總結:結構體指標可以通過 -> 運算子 來訪問結構體中的成員
1.5.結構體巢狀結構體
作用: 結構體中的成員可以是另一個結構體
**例如:**每個老師輔導一個學員,一個老師的結構體中,記錄一個學生的結構體
示例:
//学生结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
//教师结构体定义
struct teacher
{
//成员列表
int id; //职工编号
string name; //教师姓名
int age; //教师年龄
struct student stu; //子结构体 学生
};
int main() {
struct teacher t1;
t1.id = 10000;
t1.name = "老王";
t1.age = 40;
t1.stu.name = "张三";
t1.stu.age = 18;
t1.stu.score = 100;
cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl;
cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl;
return 0;
}
執行結果:
教师 职工编号: 10000 姓名: 老王 年龄: 40
辅导学员 姓名: 张三 年龄:18 考试分数: 100
**總結:**在結構體中可以定義另一個結構體作為成員,用來解決實際問題
1.6.結構體做函式引數
**作用:**將結構體作為引數向函式中傳遞
傳遞方式有兩種:
- 值傳遞
- 地址傳遞
示例:
//学生结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
//值传递
void printStudent(student stu )
{
stu.age = 28;
cout << "子函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
}
//地址传递
void printStudent2(student *stu)
{
stu->age = 28;
cout << "子函数中 姓名:" << stu->name << " 年龄: " << stu->age << " 分数:" << stu->score << endl;
}
int main() {
student stu = { "张三",18,100};
//值传递
printStudent(stu);
cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
cout << endl;
//地址传递
printStudent2(&stu);
cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
return 0;
}
執行結果:
子函数中 姓名:张三 年龄: 28 分数:100
主函数中 姓名:张三 年龄: 18 分数:100
子函数中 姓名:张三 年龄: 28 分数:100
主函数中 姓名:张三 年龄: 28 分数:100
總結:如果不想修改主函式中的資料,用值傳遞,反之用地址傳遞
1.7.結構體中 const使用場景
**作用:**用const來防止誤操作
示例:
//学生结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
//const使用场景
void printStudent(const student *stu) //加const防止函数体中的误操作
{
//stu->age = 100; //操作失败,因为加了const修饰
cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl;
}
int main() {
student stu = { "张三",18,100 };
printStudent(&stu);
return 0;
}
執行結果:
姓名:张三 年龄:18 分数:100
1.8.結構體案例
1.8.1.案例1
案例描述:
學校正在做畢設專案,每名老師帶領5個學生,總共有3名老師,需求如下
設計學生和老師的結構體,其中在老師的結構體中,有老師姓名和一個存放5名學生的陣列作為成員
學生的成員有姓名、考試分數,建立陣列存放3名老師,通過函式給每個老師及所帶的學生賦值
最終打印出老師資料以及老師所帶的學生資料。
示例:
struct Student
{
string name;
int score;
};
struct Teacher
{
string name;
Student sArray[5];
};
void allocateSpace(Teacher tArray[] , int len)
{
string tName = "教师";
string sName = "学生";
string nameSeed = "ABCDE";
for (int i = 0; i < len; i++)
{
tArray[i].name = tName + nameSeed[i];
for (int j = 0; j < 5; j++)
{
tArray[i].sArray[j].name = sName + nameSeed[j];
tArray[i].sArray[j].score = rand() % 61 + 40;
}
}
}
void printTeachers(Teacher tArray[], int len)
{
for (int i = 0; i < len; i++)
{
cout << tArray[i].name << endl;
for (int j = 0; j < 5; j++)
{
cout << "\t姓名:" << tArray[i].sArray[j].name << " 分数:" << tArray[i].sArray[j].score << endl;
}
}
}
int main() {
srand((unsigned int)time(NULL)); //随机数种子 头文件 #include <ctime>
Teacher tArray[3]; //老师数组
int len = sizeof(tArray) / sizeof(Teacher);
allocateSpace(tArray, len); //创建数据
printTeachers(tArray, len); //打印数据
return 0;
}
執行結果(隨機數會隨執行環境變化,以下為一次執行示例;型別大小或型別名可能隨編譯器和平臺變化):
教师A
姓名:学生A 分数:81
姓名:学生B 分数:43
姓名:学生C 分数:88
姓名:学生D 分数:95
姓名:学生E 分数:81
教师B
姓名:学生A 分数:78
姓名:学生B 分数:73
姓名:学生C 分数:85
姓名:学生D 分数:99
姓名:学生E 分数:54
教师C
姓名:学生A 分数:42
姓名:学生B 分数:79
姓名:学生C 分数:74
姓名:学生D 分数:100
姓名:学生E 分数:89
1.8.2.案例2
案例描述:
設計一個英雄的結構體,包括成員姓名,年齡,性別;建立結構體陣列,陣列中存放5名英雄。
通過氣泡排序的演算法,將陣列中的英雄按照年齡進行升序排序,最終列印排序後的結果。
五名英雄資訊如下:
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
示例:
//英雄结构体
struct hero
{
string name;
int age;
string sex;
};
//冒泡排序
void bubbleSort(hero arr[] , int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j].age > arr[j + 1].age)
{
hero temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//打印数组
void printHeros(hero arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << "姓名: " << arr[i].name << " 性别: " << arr[i].sex << " 年龄: " << arr[i].age << endl;
}
}
int main() {
struct hero arr[5] =
{
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},
};
int len = sizeof(arr) / sizeof(hero); //获取数组元素个数
bubbleSort(arr, len); //排序
printHeros(arr, len); //打印
return 0;
}
執行結果(型別大小或型別名可能隨編譯器和平臺變化):
姓名: 貂蝉 性别: 女 年龄: 19
姓名: 张飞 性别: 男 年龄: 20
姓名: 赵云 性别: 男 年龄: 21
姓名: 关羽 性别: 男 年龄: 22
姓名: 刘备 性别: 男 年龄: 23
2.
2.1.結構體在 C 和 C++ 中的寫法差異
2.1.1.定義結構體
結構體定義由關鍵字 struct 和結構體名組成,結構體名可以根據需要自行定義。
struct 語句定義了一個包含多個成員的新的資料型別,struct 語句的格式如下:
struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
2.1.2.訪問結構體成員
下面是宣告一個結構體型別 Books ,變數為 book, 為了訪問結構的成員,我們使用 成員訪問運算子(.) 。成員訪問運算子是結構變數名稱和我們要訪問的結構成員之間的一個句號。
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
book.book_id = 1;
strcpy(book.title,"春天");
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
typedef struct Books //Books可忽略不写
{
char title[50];
char author[50];
char subject[100];
int book_id;
}Books_Rename;
struct Books book; //第一种写法,不使用typedf必须加 struct 定义结构体
Books_Rename book; //用typedef后的写法,9,11行不能共存,因为变量名相同。
book.book_id = 1;0
strcpy(book.title,"春天");
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
2.1.3.指向結構的指標
您可以定義指向結構的指標,方式與定義指向其他型別變數的指標相似,如下所示:
struct Books *struct_pointer;
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
現在,您可以在上述定義的指標變數中儲存結構變數的地址。為了查詢結構變數的地址,請把 & 運算子放在結構名稱的前面,如下所示:
struct_pointer = &Book1;
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
為了使用指向該結構的指標訪問結構的成員,您必須使用 -> 運算子,如下所示:
struct_pointer->title;
(*struct_pointer).title;
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
2.1.4.結構體與函式
- 作為函式引數
struct Books
{
···
int book_id;
} book;
void fun1(Books book){
}
//通常使用指针传递
void fun2(Books *book){
}
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
- 作為函式返回型別
2.1.5.C++中的結構體
- 定義 與上述定義一致,不同的是,在 C++ 中即使不使用 typedef struct 來定義結構體,定義結構體變數時也無需在變數前加 struct
//定义结构体
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
//定义结构体变量
book book1;
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
- 物件導向
struct預設的成員和繼承是public
struct Books
{
public://默认
string title;
string author;
string subject;
int book_id;
//构造函数
Books(string t,string author,string subject,int id){
title = t;
author = author;
subject = subject;
book_id = id;
}
//析构函数
~Books(){
...
}
//成员函数
void fun1(){
...
}
private:
protected:
};
//初始化结构体
Books book1("title","author","subject",1);
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
2.2.共用體 union
共用體 是一種特殊的資料型別,允許您在相同的記憶體位置儲存不同的資料型別。您可以定義一個帶有多成員的共用體,但是任何時候只能有一個成員帶有值。共用體提供了一種使用相同的記憶體位置的有效方式。
2.2.1.定義共用體
為了定義共用體,您必須使用 union 語句,方式與定義結構類似。union 語句定義了一個新的資料型別,帶有多個成員。union 語句的格式如下:
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
//举例:
union Type_Name
{
int i;
float f;
char str1[20];
string str2;
} object_name;
//调用方式
object_name.i = 5;
object_name.f = 6.0f;
object_name.str2 = "你好!";
執行結果: 此程式碼塊不含 main 函式,是語法、介面或分檔案示例,不能獨立執行,因此沒有終端輸出。
注意:共用體所佔記憶體大小,按成員變數需佔記憶體最大的來。