十八、函数(一)
1、函数概述
1)函数带来的好处
①代码模块化,便于阅读维护
②代码模块化以后,能够实现分工合作
③减少重复代码,降低工作流
2)函数的语法
//函数的语法
返回类型 函数名称(参数,参数,参数,参数) //参数的语法包括:参数类型 参数名称
{
函数的功能区;
return 返回值;
}
//函数的声明示范一
int Add(int a,int b)
{
return a+b;
}
使用:
int a=Add(100,200); //a=300
//函数的声明示范二
void PrintLog(char *str)
{
std::cout<<"日志:"<<str;
}
使用:
Printlog("你好世界!");
//函数的声明示例
// 函数一.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
int Add(int a, int b) //函数的声明
{
return a + b; ////返回的是什么类型的值,就用什么类型接受
}
//不需要返回值的函数,使用的返回类型为void
void PrintEnding(const char* str,int x)
{
std::cout << str << x << std::endl;
}
int main()
{
int x{ Add(100, 100) }; //函数的使用
PrintEnding("生命值:",x);
x =Add(200,300);
PrintEnding("内力值:",x);
}
注:每个函数都必须有return函数返回值,main()函数编译器会自动在函数结尾默认加一个return
//用函数实现游戏麟江湖排行榜设计修
//GetDataCount函数统计有几个角色的信息
int GetDataCount(string str)
{
int icount{};
for (int i = 0; i < str.length(); i++)
{
if (str[i] == ';')
{
icount++;
i += 3;
}
}
return icount/2;
}
//获取字符串中的数据
string GetDataStr(string str, int istart)
{
string strReturn{};
int iend{};
istart = str.find("id=", istart);
if (istart == std::string::npos) return strReturn;
iend = str.find(";", istart + 3);
strReturn = str.substr(istart + 3, iend - istart - 3);
return strReturn;
}
2、函数参数之指针参数
函数分为三部分:包括函数的头部、函数体、函数的尾部(一个函数有可能有很多尾部)、
函数头中的变量只申请了内存空间、但是没有赋值,没有初始化
函数尾是为了返回值
//直接将实参传递给形参
#include <iostream>
int Add(int x, int y) //形参
{
x *= 100;
y *= 100;
return x + y;
}
int main()
{
int x = 2, y = 1;
int c = Add(x,y); //实参
std::cout << "c=" << c << " x=" << x << " y=" << y << std::endl;
}
//通过此种方式无法得到x和y变化后的结果
//向函数中传入指针参数(将函数中的值读取去出来,获得回传值)
#include <iostream>
int Add(int* x, int* y) //形参
{
(*x) *= 100; //x和y次数是一个指针
(*y) *= 100;
return (*x) + (*y);
}
int main()
{
int x = 2, y = 1;
int c = Add(&x, &y); //实参传入x和y的内存地址
std::cout << "c=" << c << " x=" << x << " y=" << y << std::endl;
}
//通过结果发现c的值没有发生变化,但是x和y的值发生了变化。成为函数中最终计算的x和y的结果
2)指针参数的常见应用
函数头部中的形参在定义时,会分配整个结构体内部成员变量总和的内存空间,会存在内存空间开销过剩的问题;但是如果函数头部中传入的参数为指针参数,那么只需要分配指针大小的函数空间,即4字节.
//不使用指针参数,给函数传值
#include <iostream>
struct Role
{
int Hp;
int Mp;
};
int Exp(Role role)
{
return role.Hp + role.Mp;
}
int main()
{
Role role{ 500,1000 };
int totle =Exp(role); //看起来函数在调用时传入了一个参数,但是实际上传入了两个参数
std::cout << "角色战斗力为:" << totle << std::endl;
}
//通过指针参数,给函数传值
#include <iostream>
struct Role
{
int Hp;
int Mp;
};
int Exp(Role* role)
{
return role->Hp + role->Mp; //不再使用.取实体,而是通过->偏移符号通过地址传值
}
int main()
{
Role role{ 500,1000 };
int totle = Exp(&role); //取地址
std::cout << "角色战斗力为:" << totle << std::endl;
}
//通过此方式可大大提升效率
3)指针参数之常量指针用法
回顾:常量指针,表示指针指向的内容是一个常量,指针指向的内容不可以发生变化,即值可以读,但不可以写,防止修改数据
//初始化一个玩家和怪物,定义一个函数,返回一个bool值,当值为true的时候,说明角色死亡
#include <iostream>
struct Role
{
int Hp;
int Mp;
int damage;
};
bool Exp(const Role* Acter, Role* beActer) //攻击者者和被攻击者,攻击者的属性不能够修改
{
beActer->Hp -= Acter->damage; //被攻击者血量=被攻击者血量-攻击者伤害值
return beActer->Hp <= 0;
}
int main()
{
Role user{ 500,1000,1200 };
Role monster{ 1500,1000,1000 };
if (Exp(&monster, &user))
std::cout << "角色死亡!" << std::endl;
else
if (Exp(&user ,&monster))
std::cout << "怪物死亡" << std::endl;
}
3、函数参数之数组参数
1)数组本质上就是一个指针,传入数组参数时,要传入数组的长度。提高如下两种数组参数的定义方法
//传入数组参数时,必须要传入数组的长度
//数组参数方法一
Void Sort(int ary[],unsigned count) //推荐
{
for(int i=1;i<count;i++)
}
int main()
{
int a[5]{ 2302,5212,3653,9480,5200 };
Sort(a, 5);
}
//数组参数方法一
Void Sort(int* ary,unsigned count) //推荐
{
for(int i=1;i<count;i++)
}
int main()
{
int a[5]{ 2302,5212,3653,9480,5200 };
Sort(a, 5);
}
//将数组进行排序案例
#include <iostream>
void Sort(int ary[],unsigned count)
{
for (int i = 1; i < count; i++)
{
if (ary[i] > ary[i - 1])
{
int tmp = ary[i];
ary[i] = ary[i - 1];
ary[i - 1] = tmp;
}
}
}
int main()
{
int a[5]{ 2302,5212,3653,9480,5200 };
Sort(a, 5);
for (auto x : a)std::cout << x << std::endl;
}
2)多维数组的传参
//多维数组的传参,无法写成指针的形式
Void Sort(int ary[][2],unsigned count) //推荐
{
f
}
int main()
{
int a[3][2]{{1,2},{3,4},{5,6}};
Sort(a, 3); //传入数组的长度
}
4、函数参数之引用参数
//引用回顾
int a=5;
int &b = a; //引用就相当于被阉割了的指针
则b++就相当于a++
1)引用也可以使用const进行限定只能读,不能写
#include <iostream>
struct Role
{
int Hp;
int Mp;
int damage;
};
bool Exp(const Role& Acter, Role& beActer) //引用,相当于Role& Acter = user;Role& beActer=monster
{
beActer.Hp -= Acter.damage;
return beActer.Hp <= 0;
}
int main()
{
Role user{ 5000,1000,12000 };
Role monster{ 1500,1000,1000 };
if (Exp(user, monster))std::cout << "怪物死亡,获得经验值XXX" << std::endl;
}
2)引用和指针的区别
引用要想使用,必须先得初始化;而指针可以先传入一个空指针,先不进行初始化
//此种方式错误,引用必须初始化
bool Act(Role& Acter,Role& beAct)
{
return true;
}
Act(nullptr,nullptr);
//指针可以不进行初始化
bool Act(Role* Acter,Role* beAct)
{
return true;
}
Act(nullptr,nullptr);
3)指针类型的引用
//指针类型的引用
#include <iostream>
struct Role
{
char name[0x20];
int Hp;
int Mp;
int damage;
};
bool Exp(const Role& Acter, Role*& beActer) //Role*指针类型的引用
{
beActer->Hp -= Acter.damage;
bool End = beActer->Hp < 0;
beActer = (Role*)&Acter; //通过指针类型的引用,可以修改参数的指向,此处将被攻击者修改为攻击者
return End;
}
int main()
{
Role user{ "奥特曼",5000,1000,12000 };
Role monster{ "小怪兽",1500,1000,1000 };
Role* pRole = &monster;
if (Exp(user, pRole))std::cout << pRole->name<<" 怪物死亡,获得经验值XXX" << std::endl;
}
可以使用如下写法
//指针类型的引用的其他写法
#include <iostream>
typedef struct Role
{
char name[0x20];
int Hp;
int Mp;
int damage;
}*PROLE; //Role类型的指针PROLE
bool Exp(const Role& Acter, PROLE& beActer) //Role类型指针PROLE的引用
{
beActer->Hp -= Acter.damage;
bool End = beActer->Hp < 0;
beActer = (Role*)&Acter; //通过指针类型的引用,可以修改参数的指向,此处将被攻击者修改为攻击者
return End;
}
int main()
{
Role user{ "奥特曼",5000,1000,12000 };
Role monster{ "小怪兽",1500,1000,1000 };
PROLE pRole = &monster; ////Role类型指针PROLE
if (Exp(user, pRole))std::cout << pRole->name<<" 怪物死亡,获得经验值XXX" << std::endl;
}
5、函数参数之默认实参
1)默认参数引入
//传入一组数,对其进行排序
#include <iostream>
void Swap(int &a,int &b) //定义函数专门用来交换两个数
{
int tmp = a;
a = b;
b = tmp;
}
void Sort(int ary[], unsigned count,bool BigSort) //定义函数用来排序
{
for(int i=1;i<count;i++)
{
bool bcase = BigSort ? ary[i] > ary[i - 1]:ary[i - 1] > ary[i];
if (bcase)Swap(ary[i], ary[i - 1]);
}
}
int main()
{
int a[5]{ 2302,5212,3653,9480,5200 };
Sort(a, 5,false); //true表示从大到小排序,false表示从小到大排序
for (auto x : a)std::cout << x << std::endl;
}
2)默认参数使用
在函数调用时,若不传递值,则使用函数声明时设置的默认参数。默认参数只可以放置在最后,不可以放置在最前面或中间;若有多个默认参数,需要依次写在最后面
//默认参数使用
#include <iostream>
void Swap(int &a,int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void Sort(int ary[], unsigned count,bool BigSort=true) //定义函数默认值参数
{
for(int i=1;i<count;i++)
{
bool bcase = BigSort ? ary[i] > ary[i - 1]:ary[i - 1] > ary[i];
if (bcase)Swap(ary[i], ary[i - 1]);
}
}
int main()
{
int a[5]{ 2302,5212,3653,9480,5200 };
Sort(a, 5); //函数调用时,若不传入参数,默认使用函数声明时形参的默认值
for (auto x : a)std::cout << x << std::endl;
}
6、函数参数之不定量参数(一)
//main()函数的另一面
int main(int argcount,char* c_arg[])
{
std::cout<<"参数个数:"<<argcount;
}
//argcount表示传入的参数个数,即有效参数
//char* c_arg[]为指针数组,表示要传入的参数,第一个参数为程序的路径及文件名,最后一个参数为nullptr空指针,即无效参数
原理:将字符串通过空格打断,依次将字符串的地址放入了指针数组中
#include <iostream>
int main(unsigned argcount,char* arg[])
{
for (int i = 0; i < argcount; i++)
{
std::cout << "第" << i << "个参数的值为" << arg[i] << ",地址为" << (int)arg[i] << std::endl;
}
}
7、麟江湖注册命令的设计
项目需求:设计麟江湖的注册程序linReg.exe
1)用户在控制台输入linReg和相关参数可以完成注册账号的操作
2)用户输入linReg /?可以得到相关的帮助文档
3)程序中用到的字符处理相关函数均需自己设计
4)自行设计注册账户的参数,可以参照如下
linReg id:tigerinf pass:handsome country:China
结果显示:
注册成功!
=========================================
linReg id:tigerinf pass:handsome country:China
点击项目属性-常规-目标文件名修改为要生成的exe程序名称,此处为linReg
重新生成解决方案,应用名称就是linReg.exe
#include <iostream>
//linReg id:tigerinf pass:handsome country:China
char* ReadRef(const char* ref, const char* cmds) //第一个参数读取id:后面的内容即tigerinf,第二个参数为整个传入的参数。因为只读取,不修改。所以使用const
//先从首字母比较,即将id:的第一个字符i与完整的字符串比较。如果一样,继续比较,否则跳过去,继续比较下一个字符d,依次比较,如果一致,则返回
{
//id:tigerinf pass:handsome country:China
for (int i = 0; cmds[i]; i++)
{
if (cmds[i] == ref[0]) ////将长字符串的第一个字符和参数的第一个字符依次比较
{
bool bfind = true;
int x = 0; //len用于计算参数的长度,即pass:的长度
for (x = 0; ref[x]; x++) //ref[x]=0,表示字符串已经结束了
{
if (ref[x] != cmds[i + x])
{
bfind = false;
break;
}
}
if (bfind)return (char*)&cmds[i + x]; //因cmds[i+x]是字符,而此处需要返回其位置,指针,所以要加&符号
}
}
return nullptr; //如果循环完成,一直没有找到字符串,则返回空指针
}
int main(int count, char* arc[])
{
char* id{};
char* pass{};
char* country{};
const char* idRef{"id:"};
const char* passRef{ "pass:" };
const char* countryRef{ "country:" };
for (int i = 1; arc[i]; i++)
{
if(id==nullptr)
{
id = ReadRef(idRef, arc[i]);
if (id != nullptr)continue;
}
if (pass == nullptr)
{
pass = ReadRef(passRef, arc[i]);
if (pass != nullptr)continue;
}
if (country == nullptr)
{
country = ReadRef(countryRef, arc[i]);
if (country != nullptr)continue;
}
}
if((int)id * (int)pass * (int)country)
{
std::cout << "注册成功" << std::endl;
std::cout << "================================" << std::endl;
std::cout << "账号" << id << std::endl;
std::cout << "密码" << pass << std::endl;
std::cout << "国家" << country << std::endl;
}
else
{
std::cout << "请使用命令的方式调用本程序!!!" << std::endl;
}
}