結構體與共用體
結構體
結構體基本概念
結構體屬於用户==自定義的數據類型==,允許用户存儲不同的數據類型
結構體定義和使用
語法: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;
}
運行/觀察結果: 運行後會按輸出語句打印對應內容,變量值可結合初始化、賦值和函數調用順序推導。
總結1:定義結構體時的關鍵字是struct,不可省略
總結2:創建結構體變量時,關鍵字struct可以省略
總結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;
}
運行/觀察結果: 運行後會按輸出語句打印對應內容,變量值可結合初始化、賦值和函數調用順序推導。
結構體指針
**作用:**通過指針訪問結構體中的成員
- 利用操作符
->可以通過結構體指針訪問結構體屬性
示例:
//结构体定义
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;
}
運行/觀察結果: 運行後會打印示例中的變量值或地址;地址值與運行環境有關,以同類對象的相對位置和指針變化為觀察重點。
總結:結構體指針可以通過 -> 操作符 來訪問結構體中的成員
結構體嵌套結構體
作用: 結構體中的成員可以是另一個結構體
**例如:**每個老師輔導一個學員,一個老師的結構體中,記錄一個學生的結構體
示例:
//学生结构体定义
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;
}
運行/觀察結果: 運行後會按輸出語句打印對應內容,變量值可結合初始化、賦值和函數調用順序推導。
**總結:**在結構體中可以定義另一個結構體作為成員,用來解決實際問題
結構體做函數參數
**作用:**將結構體作為參數向函數中傳遞
傳遞方式有兩種:
- 值傳遞
- 地址傳遞
示例:
//学生结构体定义
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;
}
運行/觀察結果: 運行後會打印示例中的變量值或地址;地址值與運行環境有關,以同類對象的相對位置和指針變化為觀察重點。
總結:如果不想修改主函數中的數據,用值傳遞,反之用地址傳遞
結構體中 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;
}
運行/觀察結果: 運行後會打印示例中的變量值或地址;地址值與運行環境有關,以同類對象的相對位置和指針變化為觀察重點。
結構體案例
案例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;
}
運行/觀察結果: 運行結果包含隨機數或時間相關內容,每次執行可能不同,重點觀察生成和處理流程。
案例2
案例描述:
設計一個英雄的結構體,包括成員姓名,年齡,性別;創建結構體數組,數組中存放5名英雄。
通過冒泡排序的算法,將數組中的英雄按照年齡進行升序排序,最終打印排序後的結果。
五名英雄信息如下:
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},
運行/觀察結果: 這段是語法或接口示例,重點觀察寫法;放入完整程序後再運行驗證。
示例:
//英雄结构体
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;
}
運行/觀察結果: 運行後會按輸出語句打印對應內容,變量值可結合初始化、賦值和函數調用順序推導。
結構體在 C 和 C++ 中的寫法差異
定義結構體
結構體定義由關鍵字 struct 和結構體名組成,結構體名可以根據需要自行定義。
struct 語句定義了一個包含多個成員的新的數據類型,struct 語句的格式如下:
struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
運行/觀察結果: 這段偏語法定義,通常需要配合調用代碼一起編譯,重點看定義方式和使用位置。
訪問結構體成員
下面是聲明一個結構體類型 Books ,變量為 book, 為了訪問結構的成員,我們使用 成員訪問運算符(.) 。成員訪問運算符是結構變量名稱和我們要訪問的結構成員之間的一個句號。
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
book.book_id = 1;
strcpy(book.title,"春天");
運行/觀察結果: 這段偏語法定義,通常需要配合調用代碼一起編譯,重點看定義方式和使用位置。
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,"春天");
運行/觀察結果: 這段偏語法定義,通常需要配合調用代碼一起編譯,重點看定義方式和使用位置。
指向結構的指針
您可以定義指向結構的指針,方式與定義指向其他類型變量的指針相似,如下所示:
struct Books *struct_pointer;
運行/觀察結果: 這段偏語法定義,通常需要配合調用代碼一起編譯,重點看定義方式和使用位置。
現在,您可以在上述定義的指針變量中存儲結構變量的地址。為了查找結構變量的地址,請把 & 運算符放在結構名稱的前面,如下所示:
struct_pointer = &Book1;
運行/觀察結果: 這段是語法或接口示例,重點觀察寫法;放入完整程序後再運行驗證。
為了使用指向該結構的指針訪問結構的成員,您必須使用 -> 運算符,如下所示:
struct_pointer->title;
(*struct_pointer).title;
運行/觀察結果: 這段是語法或接口示例,重點觀察寫法;放入完整程序後再運行驗證。
結構體與函數
- 作為函數參數
struct Books
{
···
int book_id;
} book;
void fun1(Books book){
}
//通常使用指针传递
void fun2(Books *book){
}
運行/觀察結果: 這段偏語法定義,通常需要配合調用代碼一起編譯,重點看定義方式和使用位置。
- 作為函數返回類型
C++中的結構體
- 定義 與上述定義一致,不同的是,在 C++ 中即使不使用 typedef struct 來定義結構體,定義結構體變量時也無需在變量前加 struct
//定义结构体
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
//定义结构体变量
book book1;
運行/觀察結果: 這段偏語法定義,通常需要配合調用代碼一起編譯,重點看定義方式和使用位置。
- 面向對象
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);
運行/觀察結果: 這段是語法片段,重點看寫法;補全上下文後再運行。
共用體 union
共用體 是一種特殊的數據類型,允許您在相同的內存位置存儲不同的數據類型。您可以定義一個帶有多成員的共用體,但是任何時候只能有一個成員帶有值。共用體提供了一種使用相同的內存位置的有效方式。
定義共用體
為了定義共用體,您必須使用 union 語句,方式與定義結構類似。union 語句定義了一個新的數據類型,帶有多個成員。union 語句的格式如下:
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
運行/觀察結果: 這段是語法片段,重點看寫法;補全上下文後再運行。
//举例:
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 = "你好!";
運行/觀察結果: 這段是語法或接口示例,重點觀察寫法;放入完整程序後再運行驗證。
注意:共用體所佔內存大小,按成員變量需佔內存最大的來。