【C++学习】结构体
Published in:2024-08-10 | category: C++
Words: 2.1k | Reading time: 9min | reading:

发现个好东西,试一下子

图片描述

定义

结构体属于用户自定义的数据类型,允许用户存储不同的数据类型

创建结构体变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;

system("pause");

return 0;
}

创建结构体变量时,关键词struct可以省略

结构体变量利用操作符”.”访问成员

结构体数组

作用: 将自定义的结构体放入到数组中方便维护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main() {

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;
}

system("pause");

return 0;
}

结构体指针

作用: 通过指针访问结构体中的成员

利用操作符’->’可以通过结构体指针访问结构体属性

在C语言中,结构体变量和结构体指针访问成员的方式不同,这是由于它们在内存中的存储和访问机制不同。
结构体变量使用.操作符访问成员,因为结构体变量本身就是一个具体的实例,它包含了所有成员的数据。当你使用.操作符时,你直接在结构体实例上访问其成员。
例如,如果你有一个名为student的结构体,并且有一个student类型的变量stu,你可以这样访问它的成员:

1
2
3
4
5
6
7
8
9
struct student {
char name[20];
int age;
int score;
};
struct student stu = {"张三", 18, 100};
printf("%s\n", stu.name); // 使用 '.' 操作符访问结构体成员
printf("%d\n", stu.age);
printf("%d\n", stu.score);

而结构体指针使用->操作符访问成员,因为指针本身并不直接包含结构体的数据,而是存储了结构体数据的内存地址。当你使用->操作符时,你实际上是在告诉编译器:“请先到这个地址去找到结构体实例,然后再访问它的成员。”
例如,如果你有一个指向student结构体的指针ptr,你可以这样访问它的成员:

1
2
3
4
struct student *ptr = &stu;  // ptr 指向 stu 的地址
printf("%s\n", ptr->name); // 使用 '->' 操作符访问结构体成员
printf("%d\n", ptr->age);
printf("%d\n", ptr->score);

这里,ptr->name(*ptr).name的简写形式,它首先通过解引用指针*ptr来获取结构体实例,然后通过.操作符访问其name成员。
总结来说,.用于直接访问结构体变量的成员,而->用于通过结构体指针间接访问其指向的结构体实例的成员。

结构体嵌套结构体

示例:
每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct student {
string name;
int age;
int score;
};

struct teacher
{
string name;
int age;
student stu;

};

// 重载 << 运算符以便输出 student 结构体
ostream& operator<<(ostream& os, const student& s) {
os << "姓名: " << s.name << " 年龄: " << s.age << " 分数: " << s.score;
return os;
}
int main() {
student stu1 = { "时域",19,100 };

teacher tea1 = { "余新晨",20,stu1 };

teacher* p = &tea1;

cout << "姓名:" << p->name << "年龄:" << p->age << "学生:" << p->stu << endl;

system("pause");

return 0;
}

重载运算符

在C++中,运算符重载是一种功能,它允许你为类或结构体定义现有运算符的新行为。通过重载运算符,你可以使它们与用户定义的类型一起工作,就像它们与内置类型一起工作一样。下面是对operator<<重载函数的详细解释:

函数签名

1
ostream& operator<<(ostream& os, const student& s)

这里,operator<<是正在被重载的运算符,它用于输出(插入)数据到输出流中(比如标准输出cout)。函数接受两个参数:

  1. ostream& os:这是一个引用到输出流的引用,通常是一个std::ostream类型的对象,比如std::cout。使用引用是因为我们不想复制整个流对象,只是想在原对象上操作。
  2. const student& s:这是一个对student结构体的常量引用。我们使用常量引用是因为我们不想修改传入的结构体,并且引用可以避免不必要的复制。

函数体

1
os << "姓名: " << s.name << " 年龄: " << s.age << " 分数: " << s.score;

在函数体内部,我们使用了<<运算符来将结构体student的成员依次输出到传入的输出流os中。以下是步骤:

  1. os << "姓名: ":将字符串”姓名: “输出到输出流os
  2. << s.name:输出student结构体的name成员。
  3. << " 年龄: ":输出字符串” 年龄: “。
  4. << s.age:输出student结构体的age成员。
  5. << " 分数: ":输出字符串” 分数: “。
  6. << s.score:输出student结构体的score成员。

返回值

1
return os;

函数返回一个ostream对象的引用。这是为了允许链式调用,也就是说,你可以连续使用多个<<运算符,如下所示:

1
cout << "教师姓名: " << p->name << " 年龄: " << p->age << " 学生信息: " << p->stu << endl;

在这里,每次调用<<运算符后返回的ostream引用都用于下一次调用。

总结

重载operator<<允许你以自然的方式将student结构体对象输出到标准输出或其他输出流中,而无需单独输出每个成员。这样可以使代码更加简洁,可读性更强。通过返回ostream引用,你还可以继续将其他内容输出到同一个流中。

结构体做函数参数

传递方式

  1. 值传递
  2. 地址传递
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;

system("pause");

return 0;
}

如果不想修改主函数中的数据,用值传递,反之用地址传递

结构体中const使用场景

作用: 用const来防止误操作

1
2
3
4
5
6
7
//const使用场景
void printStudent(const student *stu) //加const防止函数体中的误操作
{
//stu->age = 100; //操作失败,因为加了const修饰
cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl;

}
Prev:
【C++学习】内存分区模型
Next:
【C++学习】指针