42.结构体-结构体和函数
42.1 知识点
结构体作为函数参数
struct Student
{
int age;
string name;
Student* p;
};
当结构体作为参数传递时,可以通过以下三种方式:
- 按值传递(拷贝副本传递给函数)
- 指针传递(传递结构体地址)
- 引用传递(传递原结构体)
对于小型结构体,三种方式都可以使用。对于结构复杂的结构体,建议使用引用或指针传递。
void test(Student s)
{
s.age = 99;
s.p->name = "小明";
}
Student s = { 18, "韬老狮", nullptr };
s.p = new Student{ 10, "小红", nullptr };
test(s);
cout << s.age << endl; // 18 不变 不会受到影响
cout << s.p->name << endl; // 小明 要变 要受到函数内部修改的影响 因为 p 是指针,存储的是地址
函数返回结构体
结构体和其他变量类型一样,可以作为返回值返回。需要注意以下事项:
- 不能返回局部变量(在函数内部声明的变量),因为它们的生命周期会随着函数调用的结束而结束。如果在外部继续使用这些局部变量,会出现问题。
- 除非这个局部变量是在堆上分配的空间,否则返回堆上的内容可以直接返回,因为堆上的内容需要我们自己管理释放。
- 否则只能返回静态变量、全局变量,或者是外部传入的指针或引用变量。
总结
不管变量类型是什么,只要要作为函数返回值,都必须考虑它的生命周期问题。
42.2 知识点代码
Lesson42_结构体_结构体和函数.cpp
#include <iostream>
using namespace std;
struct Student
{
int age;
string name;
Student* p;
};
void test(Student s);
int main()
{
std::cout << "结构体和函数\n";
#pragma region 知识点一 结构体作为函数参数
Student s = { 18, "韬老狮", nullptr };
s.p = new Student{ 10, "小红", nullptr };
test(s);
cout << s.age << endl;//18 不变 不会受到影响
cout << s.p->name << endl;//小明 要变 要受到函数内部修改的影响 因为p是指针 存储的是地址
#pragma endregion
}
#pragma region 知识点一 结构体作为函数参数
//当结构体作为参数传递时
//可以通过以下三种方式:
//1.按值传递(拷贝副本传递给函数)
//2.指针传递(传递结构体地址)
//3.引用传递(传递原结构体)
//对于小型结构体三种方式随便用
//对于结构复杂的建议使用引用或指针传递
void test(Student s)
{
s.age = 99;
s.p->name = "小明";
}
#pragma endregion
#pragma region 知识点二 函数返回结构体
//结构体和其他变量类型一样,可以作为返回值返回
//注意事项也是一致的,要考虑返回对象的生命周期
//函数返回值的时候
//1.不能去返回局部变量(在函数内部声明的变量)生命周期会随着函数调用的结束而结束
// 如果在外部继续去使用这种局部变量 会出现问题
//2.除非你这个局部变量时在堆上去分配的空间,那么可以直接返回,因为堆上内容需要我们自己管理释放
//3.否则就只能返回 静态变量 或者 全局变量 才可以,或者是外部传入的指针或者引用变量才行
//总结,不管变量类型是什么 只要要作为函数返回值,那我们就必须考虑它的生命周期问题
#pragma endregion
42.3 练习题
应用已学过的知识,实现奥特曼打小怪兽
提示:
结构体描述奥特曼与小怪兽
定义一个方法实现奥特曼攻击小怪兽
定义一个方法实现小怪兽攻击奥特曼
分析:
因为在攻击方法中,奥特曼和怪兽互相需要参数,但是假如直接定义会找不到
可以先声明奥特曼结构体,但不实现
然后在怪兽结构体的怪兽攻击奥特曼的方法中传入奥特曼参数,也不要实现,因为此时不知道奥特曼有哪些成员
在实现奥特曼结构体时,使用 Boss::atkOutMan 再实现怪兽攻击奥特曼的方法
// 定义结构体 OutMan,用于表示奥特曼
struct OutMan;
// 定义结构体 Boss,用于表示怪兽
struct Boss
{
string name; // 怪兽的名字
int atk; // 怪兽的攻击力
int def; // 怪兽的防御力
int hp; // 怪兽的生命值
// 构造函数,用于初始化怪兽的属性
// @param name 怪兽的名字
// @param atk 怪兽的攻击力
// @param def 怪兽的防御力
// @param hp 怪兽的生命值
Boss(string name, int atk, int def, int hp) : name(name), atk(atk), def(def), hp(hp) {}
// 怪兽攻击奥特曼的方法,接收一个 OutMan 的引用作为参数
// 之所以传递引用参数是希望在内部修改奥特曼内容,外部奥特曼对象也被修改
void atkOutMan(OutMan& outMan);
};
// 定义结构体 OutMan,用于表示奥特曼
struct OutMan
{
string name; // 奥特曼的名字
int atk; // 奥特曼的攻击力
int def; // 奥特曼的防御力
int hp; // 奥特曼的生命值
// 构造函数,用于初始化奥特曼的属性
// @param name 奥特曼的名字
// @param atk 奥特曼的攻击力
// @param def 奥特曼的防御力
// @param hp 奥特曼的生命值
OutMan(string name, int atk, int def, int hp) : name(name), atk(atk), def(def), hp(hp) {}
// 奥特曼攻击怪兽的方法,接收一个 Boss 的引用作为参数
// 之所以传递引用参数是希望在内部修改怪兽内容,外部怪兽对象也被修改
void atkBoss(Boss& monster)
{
// boss 减血,减去奥特曼攻击力-怪兽防御力
monster.hp -= (atk - monster.def);
// 输出攻击信息
cout << name << "攻击了" << monster.name << ",造成了" << atk - monster.def << "点伤害,"
<< monster.name << "还剩余" << monster.hp << "血量" << endl;
}
};
// 定义完了 OutMan 再去实现 Boss 的攻击方法
// 在对声明好的方法进行定义
// Boss 攻击奥特曼的方法
// @param outMan 奥特曼的引用
void Boss::atkOutMan(OutMan& outMan)
{
// 奥特曼减血,减去怪兽攻击力-奥特曼防御力
outMan.hp -= (atk - outMan.def);
// 输出攻击信息
cout << name << "攻击了" << outMan.name << ",造成了" << atk - outMan.def << "点伤害,"
<< outMan.name << "还剩余" << outMan.hp << "血量" << endl;
}
// 声明奥特曼和怪兽对象
// 初始化奥特曼对象,名字为"迪迦奥特曼",攻击力为 10,防御力为 5,生命值为 100
OutMan outMan = OutMan("迪迦奥特曼", 10, 5, 100);
// 初始化怪兽对象,名字为"哥斯拉",攻击力为 8,防御力为 4,生命值为 100
Boss boss = Boss("哥斯拉", 8, 4, 100);
// 开始战斗循环
while (true)
{
// 奥特曼攻击怪兽
outMan.atkBoss(boss);
// 判断怪兽是否死亡
if (boss.hp <= 0)
{
// 输出奥特曼胜利信息
cout << outMan.name << "取得胜利" << endl;
break;
}
// 怪兽攻击奥特曼
boss.atkOutMan(outMan);
// 判断奥特曼是否死亡
if (outMan.hp <= 0)
{
// 输出怪兽胜利信息
cout << boss.name << "取得胜利" << endl;
break;
}
// 提示用户按任意键继续
cout << "按任意键继续" << endl;
_getch();
}
42.4 练习题代码
Lesson42_练习题.cpp
#include <iostream>
#include <conio.h>
using namespace std;
//因为在攻击方法中 奥特曼和怪兽互相需要参数 但是假如直接定义会找不到
//可以先声明奥特曼结构体 但是不实现
//然后在怪兽结构体的怪兽攻击奥特曼的方法中 传入奥特曼参数 也不要实现 因为此时不知道奥特曼有哪些成员
//在实现奥特曼结构体
//使用 Boss::atkOutMan 再实现怪兽攻击奥特曼的方法
// 定义结构体 OutMan,用于表示奥特曼
struct OutMan;
// 定义结构体 Boss,用于表示怪兽
struct Boss
{
string name; // 怪兽的名字
int atk; // 怪兽的攻击力
int def; // 怪兽的防御力
int hp; // 怪兽的生命值
// 构造函数,用于初始化怪兽的属性
// @param name 怪兽的名字
// @param atk 怪兽的攻击力
// @param def 怪兽的防御力
// @param hp 怪兽的生命值
Boss(string name, int atk, int def, int hp) : name(name), atk(atk), def(def), hp(hp) {}
// 怪兽攻击奥特曼的方法,接收一个 OutMan 的引用作为参数
// 之所以传递引用参数是希望在内部修改奥特曼内容,外部奥特曼对象也被修改
void atkOutMan(OutMan& outMan);
};
// 定义结构体 OutMan,用于表示奥特曼
struct OutMan
{
string name; // 奥特曼的名字
int atk; // 奥特曼的攻击力
int def; // 奥特曼的防御力
int hp; // 奥特曼的生命值
// 构造函数,用于初始化奥特曼的属性
// @param name 奥特曼的名字
// @param atk 奥特曼的攻击力
// @param def 奥特曼的防御力
// @param hp 奥特曼的生命值
OutMan(string name, int atk, int def, int hp) : name(name), atk(atk), def(def), hp(hp) {}
// 奥特曼攻击怪兽的方法,接收一个 Boss 的引用作为参数
// 之所以传递引用参数是希望在内部修改怪兽内容,外部怪兽对象也被修改
void atkBoss(Boss& monster)
{
// boss 减血,减去奥特曼攻击力-怪兽防御力
monster.hp -= (atk - monster.def);
// 输出攻击信息
cout << name << "攻击了" << monster.name << ",造成了" << atk - monster.def << "点伤害,"
<< monster.name << "还剩余" << monster.hp << "血量" << endl;
}
};
// 定义完了 OutMan 再去实现 Boss 的攻击方法
// 在对声明好的方法进行定义
// Boss 攻击奥特曼的方法
// @param outMan 奥特曼的引用
void Boss::atkOutMan(OutMan& outMan)
{
// 奥特曼减血,减去怪兽攻击力-奥特曼防御力
outMan.hp -= (atk - outMan.def);
// 输出攻击信息
cout << name << "攻击了" << outMan.name << ",造成了" << atk - outMan.def << "点伤害,"
<< outMan.name << "还剩余" << outMan.hp << "血量" << endl;
}
int main()
{
std::cout << "结构体和函数\n";
// 声明奥特曼和怪兽对象
// 初始化奥特曼对象,名字为"迪迦奥特曼",攻击力为 10,防御力为 5,生命值为 100
OutMan outMan = OutMan("迪迦奥特曼", 10, 5, 100);
// 初始化怪兽对象,名字为"哥斯拉",攻击力为 8,防御力为 4,生命值为 100
Boss boss = Boss("哥斯拉", 8, 4, 100);
// 开始战斗循环
while (true)
{
// 奥特曼攻击怪兽
outMan.atkBoss(boss);
// 判断怪兽是否死亡
if (boss.hp <= 0)
{
// 输出奥特曼胜利信息
cout << outMan.name << "取得胜利" << endl;
break;
}
// 怪兽攻击奥特曼
boss.atkOutMan(outMan);
// 判断奥特曼是否死亡
if (outMan.hp <= 0)
{
// 输出怪兽胜利信息
cout << boss.name << "取得胜利" << endl;
break;
}
// 提示用户按任意键继续
cout << "按任意键继续" << endl;
_getch();
}
}
#pragma region 练习题
// 应用已学过的知识,实现奥特曼打小怪兽
// 提示:
// 结构体描述奥特曼与小怪兽
// 定义一个方法实现奥特曼攻击小怪兽
// 定义一个方法实现小怪兽攻击奥特曼
#pragma endregion
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com