结构体是用户自定义的数据类型(内置数据类型的集合),可存储不同的数据类型。
语法:struct 结构体名 { 结构体成员列表 };
例:struct Person { string name, int age};
创建结构体变量的3种方式:
(1)struct 结构体名 结构体变量名;
先创建结构体变量,再对结构体成员进行赋值(使用.
访问结构体变量的属性,即结构体成员)。
例:
struct Person p;
p.name = "Tom";
p.age = 16;
(2)struct 结构体名 结构体变量名 = { 成员1初始值 , 成员2初始值...};
创建结构体变量时进行初始化。
例:
struct Person p = {
"Tom", 16};
(3)定义结构体时即创建变量。
struct Person {
string name,
int age
} person;
注1:C++中,定义结构体时,struct关键字不可省略;创建结构体变量时,struct关键字可省略。
注2:结构体变量使用操作符.
访问结构体成员/属性,即结构体变量x.成员a
。
示例:
//结构体定义
/* 定义结构体时,struct关键字不可省略 */
struct Person {
string name;
int age;
} p1; //结构体变量创建方式1
int main() {
/* 创建结构体变量时,struct关键字可省略 */
//结构体变量创建方式2
struct Person p2;
p2.name = "Tom";
p2.age = 16;
//结构体变量创建方式3
struct Person p3 = {
"Jerry", 18};
cout << p2.name << "\t" << p2.age << endl;
cout << p3.name << "\t" << p3.age << endl;
return 0;
}
作用:将自定义的结构体变量存储至数组中,即结构体变量的数组,方便进行维护。
语法:struct 结构体名 数组名[元素个数] = { {...} , {...} , ... , {...} }
注1:对比基本数据类型的变量和数组:
基本数据类型变量:int var;
基本数据类型数组:int var[5];
结构体变量:struct Person person;
结构体数组:struct Person persons[5];
注2:定义结构体数组时,struct关键字可省略。
示例:
#include
using namespace std;
#include
/* 结构体定义 */
struct Person {
string name;
int age;
};
int main() {
/* 创建结构体数组 */
//1.定义时结构体数组时初始化(可省略struct关键字)
Person persons[3] = {
{
"Tom", 12}, {
"Jerry" , 13} };
//2.修改结构体数组元素
persons[2].name = "Lucy";
persons[2].age = 16;
/* 遍历结构体数组 */
for (int i = 0; i < sizeof(persons) / sizeof(persons[0]); i++) {
cout << "姓名:" << persons[i].name << ",年龄:" << persons[i].age << endl;
}
return 0;
}
作用:利用结构体指针访问或操作结构体成员。
注1:对比基本数据类型的指针:
基本数据类型指针:int *p = &var;
结构体指针:struct Person *p = &person;
//结构体指针类型需与结构体类型相匹配
注2:结构体指针使用操作符
->
访问结构体成员/属性,即结构体指针p -> 成员a
。
注3:定义结构体指针时,struct关键字可省略。
示例:
#include
using namespace std;
#include
/* 结构体定义 */
struct Person {
string name;
int age;
};
int main() {
//1.创建结构体变量
Person person = {
"Tom", 12};
//2.创建指向结构体变量的结构体指针(struct关键字可省略)
Person *p = &person;
//使用结构体变量访问成员
cout << "姓名:" << person.name << ",年龄:" << person.age<< endl;
//使用结构体指针访问成员
cout << "姓名:" << p->name << ",年龄:" << p->age << endl;
return 0;
}
作用: 结构体中可定义其它结构体作为成员,用于解决实际问题。
注:作为结构体成员(被包含)的结构体需预先定义,否则编译器报错:结构体A使用未定义的struct “B”。
示例:每门课程对应一个老师,课程的结构体成员记录老师结构体。
#include
using namespace std;
#include
/* teacher类型结构体需先于course类型结构体前被定义,否则编译器报错:"course::t"使用未定义的struct "teacher" */
struct teacher {
string name;
int age;
};
struct course {
string courseName;
struct teacher t;
};
int main() {
course c;
c.courseName = "C++";
c.t.name = "老王";
c.t.age = 16;
cout << "课程名:" << c.courseName << ",授课老师:" << c.t.name << ",年龄:" << c.t.age << endl;
return 0;
}
作用:将结构体作为函数的参数进行传递。
传递方式有2种:
(1)值传递:函数参数使用结构体变量接收值(结构体变量)。
(2)地址传递:函数参数使用结构体指针接收地址(结构体变量的地址)。
注1:若不希望修改实参,则使用值传递(函数形参使用
结构体类型
接收结构体变量
的实参)。形参的改变不影响实参。
注2:若希望修改实参,则使用地址传递(函数形参使用结构体指针
接收结构体变量地址
的实参)。形参的改变会影响实参。
示例:
#include
#include
using namespace std;
struct Person {
string name;
int age;
};
/* 值传递:形参的改变不影响实参 */
void func_value(struct Person person) {
person.name = "Jerry";
person.age = 15;
cout << "结构体变量作为函数参数传递:" << person.name << "\t" << person.age << endl;
}
/* 地址传递:形参的改变影响实参 */
void func_address(struct Person *p) {
p->name = "Lucy";
p->age = 20;
cout << "结构体指针作为函数参数传递:" << p->name << "\t" << p->age << endl;
}
int main(){
struct Person person = {
"Tom", 10 };
/* 结构体变量作为函数参数传递 */
func_value(person); //Jerry 15
cout << "main函数中的结果:" << person.name << "\t" << person.age << endl; //Tom 10
/* 结构体指针作为函数参数传递 */
func_address(&person); //Lucy 20
cout << "main函数中的结果:" << person.name << "\t" << person.age << endl; //Lucy 20
return 0;
}
作用:使用const可避免数据被修改的误操作(不可写)。
场景:值传递过程有更大的内存开销,会拷贝新的副本(结构体成员越多,内存占用越大)。地址传递过程(形参改为指针)可减少内存空间占用,不会拷贝新的副本且指针类型仅占用4字节;为避免数据被修改等误操作,可使用const关键字将函数形参的指针限定为常量指针,无法进行解引用赋值操作(限定为只读不可写状态)。
注1:对函数参数的结构体指针使用const关键字修饰后,无法通过结构体指针使用操作符
->
修改结构体成员的值(可读不可写
),否则编译器报错:表达式必须是可修改的左值。
注2:const关键字的作用:限定为只读状态,防止修改操作(不可写)。
示例:
struct Person {
string name;
int age;
};
/* 传递地址值:形参的改变影响实参 */
void func_address(const struct Person* p) {
//使用const关键字修饰结构体指针后,不能通过结构体指针修改结构体成员的值
//p->age = 20;
cout << "结构体指针作为函数参数传递:" << p->name << "\t" << p->age << endl;
}
int main() {
struct Person person = {
"Tom", 10 };
/* 结构体指针作为函数参数传递 */
func_address(&person); //Tom 10
cout << "main函数中的结果:" << person.name << "\t" << person.age << endl; //Tom 10
return 0;
}
练习:设计学生结构体,包含姓名与成绩,创建结构体数组存储若干名学生;使用冒泡排序实现结构体数组中学生成绩的降序排序。
#include
#include
using namespace std;
struct Student {
string name;
int score;
};
/* 冒泡排序 */
void bubbleSort(struct Student students[], int length) {
for (int i = 0; i < length - 1; i++) {
for (int j = 0; j < length - i - 1; j++) {
if(students[j].score < students[j + 1].score){
//降序排序
struct Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
}
int main() {
//创建学生结构体数组
struct Student stus[3] = {
{
"张三" , 89},
{
"李四" , 68},
{
"王五" , 95}
};
int len = sizeof(stus) / sizeof(stus[0]);
//冒泡排序:实现成绩降序排序
bubbleSort(stus, len);
for (int i = 0; i < len; i++) {
cout << "姓名:" << stus[i].name << ",成绩:" << stus[i].score << endl;
}
return 0;
}