Week05-项目6-函数封装


前言

本文主要介绍了C/C++函数的相关知识


1.功能实现与函数封装

1.1 项目需求

1. 封装login函数,实现登录
2. 封装菜单显示代码
3. 添加主循环,以实现反复操作
4. 初始化终端
5. 菜单标题居中显示
6. 实现具体功能

1.2 项目实现

#include <iostream>
#include <Windows.h>
#include "hacker.h"
#include <conio.h>
using namespace std;
#define CMDCOLS 60
#define CMDLINES 20
#define PWDSIZE 64
const string titleStr = "-----黑客攻击系统-----";
//优化1:初始化终端
void init() {
	char command[128];
	sprintf_s(command,"mode con cols=%d lines=%d",CMDCOLS,CMDLINES);
	system(command);
}

//优化2:标题居中
void titleInMiddle(string str) {
	for (int i = 0; i < (CMDCOLS - str.length()) / 2; i++)
	{
		cout << " ";
	}
	cout << str << endl;
}

//优化4:密码输入函数
void inputPwd(char* pwd, int size) {
	//123456
	char c;
	int i = 0;
	while (1)
	{
		// getch不从输入缓冲区中读取
		//在getch中,把回车按键输入,识别为回车符'\r'
		//在getchar中,把回车按键输入,识别为换行符'\n'

		c = _getch();
		if (c == '\r')
		{
			pwd[i] = '\0';
			break;
		}
		pwd[i++] = c;
		cout << '*';
	}
	cout << endl;
}

//login函数封装
void login() {
	string loginName;
	//string pwd;
	char pwd[64];

	while (true)
	{
		system("cls");
		titleInMiddle(titleStr);
		cout << "请输入账号:";
		cin >> loginName;
		cout << "请输入密码:";
		inputPwd(pwd,sizeof(pwd));
		if (loginName == "54hk" && !strcmp("123456",pwd))//strcmp相等的话会返回0
		{
			return;
		}
		else
		{
			cout << "用户名或密码错误,请重新输入" << endl;
			system("pause");
		}
	}
	
}



//clearBuffer()
void clearBuffer() {
	char tmp;
	while ((tmp = getchar()) != '\n');
}

//菜单函数封装 优化3,居中显示
void menuShow() {
	system("cls");
	titleInMiddle(titleStr);
	/*cout << "1.网站404攻击" << endl;
	cout << "2.网站篡改攻击" << endl;
	cout << "3.网站攻击记录" << endl;
	cout << "4.网站攻击修复" << endl;
	cout << "5.退出" << endl;*/
	string menuText[] = {
		"1.网站404攻击",
		"2.网站篡改攻击",
		"3.网站攻击记录",
		"4.网站攻击修复",
		"5.退出"
	};
	int num = sizeof(menuText)/sizeof(menuText[0]);
	int max = 0;
	//找到最大长度的字符串
	for (int i = 0; i < num; i++)
	{
		if (menuText[i].length() > max)
		{
			max = menuText[i].length();
		}
	}
	//垂直定向
	/*for (int i = 0; i < (CMDLINES - num)/4; i++)
	{
		cout << endl;
	}*/
	//打印菜单
	for (int i = 0; i < num; i++)
	{
		for (int j = 0; j <= (CMDCOLS - max)/2; j++)
		{
			cout << " ";
		}
		cout << menuText[i] << endl;
	}

}

//菜单选择
int menuChoise() {
	int n;
	cout << "请输入操作:";
	cin >> n;
	if (cin.fail())
	{
		cin.clear();
		//清空输入缓冲区:
		//clearBuffer();
		cin.ignore((std::numeric_limits< streamsize >::max)(), '\n');
		cout << "输入无效,请重新输入!" << endl;
		return 0;
		system("pause");
	}
	else
	{
		return n;
	}
	
}

//404攻击函数
void attack404(void) {
	char id[64];
	char response[MAXSIZE];

	system("cls");
	titleInMiddle("-----404攻击-----");
	cout << "请输入要攻击网站id:";
	scanf_s("%s",id, static_cast<unsigned char>(sizeof(id)));
	cout << "正在执行404攻击。。。" << endl;

	hk_404(id,response);

	string ret = UTF8ToGBK(response);
	cout << ret << endl;
	system("pause");
}

//网站篡改攻击
void webDeface(void) {
	char id[64];
	char response[MAXSIZE];
	string attackText;
	
	system("cls");
	titleInMiddle("-----网站篡改攻击-----");
	cout << "请输入要攻击网站id:";
	scanf_s("%s", id, static_cast<unsigned int>(sizeof(id)));
	cout << "请输入要嵌入的文本:";
	cin >> attackText;

	GBKToUTF8(attackText);
	hk_tamper(id, (char*)attackText.c_str(), response);
	cout << "网站篡改执行中..." << endl;

	string ret = UTF8ToGBK(response);
	cout << ret << endl;
	system("pause");
}

//攻击记录
void attackRecord(void) {
	char id[64];
	char response[MAXSIZE];

	system("cls");
	titleInMiddle("-----查询攻击记录-----");
	cout << "请输入要查询网站的id:";
	scanf_s("%s", id, static_cast<unsigned int>(sizeof(id)));
	hk_record(id, response);
	cout << "攻击记录查询中..." << endl;

	string ret = UTF8ToGBK(response);
	cout << ret << endl;
	system("pause");
}
//恢复
void attackRequire(void) {

	char id[64];
	char response[MAXSIZE];

	system("cls");
	titleInMiddle("-----网站攻击修复-----");
	cout << "请输入要修复网站id:";
	scanf_s("%s", id, static_cast<unsigned int>(sizeof(id)));

	cout << "修复中..." << endl;

	hk_restore(id,response);
	
	string ret = UTF8ToGBK(response);
	cout << ret << endl;
	system("pause");
}

int main(void) {	
	init();
	login();
	while (true)
	{
		menuShow();
		int n = menuChoise();
		switch (n)
		{
		case 1:
			attack404();
			break;
		case 2:
			webDeface();
			break;
		case 3:
			attackRecord();
			break;
		case 4:
			attackRequire();
			break;
		case 5:
			return 0;
			break;
		default:
			cout << "请输入正确的操作!" << endl;
			system("pause");
			break;
		}
	}
	
	
	return 0;
}

2.函数的定义、声明和调用

2.1 函数的定义

函数的定义:
  返回值类型 函数名(形参列表){
     函数体
  }

2.2 函数的声明和调用

在这里插入图片描述

2.3 函数的设计方法

函数的设计方法:
1)先确定函数的功能
2)确定函数的参数
是否需要参数,参数的个数,参数的类型
3)确定函数的返回值
是否需要返回值,返回值的类型
4)确定函数名
函数名, 一定要顾名思义.
5)函数名的命名方法, 和变量名相同
6) 函数的实现

#include <iostream>
#include <Windows.h>

using namespace std;

/*
	函数的定义:
		返回值类型 函数名(形参列表){
			函数体
		}
*/
int sub(int a,int b) {
	return a + b;
}

int mul(int a, int b) {
	return a - b;
}

/*
	函数的声明
		函数可以放在任意位置
*/
int sum(int n);
//int sum(int);//函数声明时也可以省略形参名
void menu() {
	cout << "1.加法运算" << endl;
	cout << "2.减法运算" << endl;
	cout << "3.累加计算" << endl;
	cout << "4.退出" << endl;
}

int main(void) {
	
	int choice,a,b,ret;
	
	while (true)
	{
		system("cls");
		menu();
		cout << "请选择:";
		cin >> choice;
		switch (choice)
		{
		case 1:
			system("cls");
			cout << "请输入加数和被加数:" << endl;
			cin >> a >> b;
			ret = sub(a,b);  //函数定义将实参的值传递给形参
			cout << "结果是:" << ret << endl;
			system("pause");
			break;
		case 2:
			system("cls");
			cout << "请输入减数和被减数:" << endl;
			cin >> a >> b;
			ret = mul(a, b);
			cout << "结果是:" << ret << endl;
			system("pause");
			break;
		case 3:
			system("cls");
			cout << "请输入要累加数:" << endl;
			cin >> a;
			ret = sum(a);    
			cout << "结果是:" << ret << endl;
			system("pause");
			break;
		case 4:
			return 0;
		default:
			cout << "请输入正确的操作!" << endl;
			system("pause");
			break;
		}
		
	}
	
	system("pause");
	return 0;
}


int sum(int n) {
	int sum = 0;
	for (int i = 0; i <= n; i++)
	{
		sum += i;
	}
	return sum;
}



3.函数普通参数的传递方式

#include <iostream>
#include <Windows.h>

using namespace std;

int add(int a, int b) { //这里在函数定义时,参数列表里的参数称为形参(形式参数)
	a = a + b;
	cout << a << endl;
	return a;
}


int main(void) {
	int x = 1, y = 1;
	cout << x << endl;
	/*  
		这里调用函数实际上是将实参x的值赋值给形参a,
		即 a = x,在程序执行中,a与x变量的地址并不相同
	*/
	add(x, y); //这里函数调用时参数列表x,y为称为实参(实际参数)
	cout << x << endl;
	

	system("pause");
	return 0;
}


4.数组作为函数的参数与默认参数

#include <iostream>
#include <Windows.h>

using namespace std;

/*
	数组在作为形参时,实际上实参传递的是一个指针。
	即,形参与实参指向了同一内存空间,所以当在函数中用形参改变数组时,实参也会变
	//x64 指针长度为8,x86(即32位) 指针长度为4
*/


void scoreTest(int score[3]) { 
	 cout << sizeof(score) << endl;
}
void scorePrint(int score[], int n) { // 这样的写法更直观,n是数组长度
	for (int i = 0; i < n; i++)
	{
		cout << score[i] << endl;
	} 
}
/*
	默认参数:如果调用函数时,没有给默认参数赋值,就用默认的
	c语言不支持默认参数
	默认参数, 只能出现在参数列表的最后, 即默认参数后面, 不能有普通参数
*/
void scoreAdd(int score[], int n, int val = 4) {
	for (int i = 0; i < n; i++)
	{
		score[i] += val;
	}
}

int main(void) {
	int score[3] = { 99,98,97 };
	int n = sizeof(score) / sizeof(score[0]);//计算数组长度
	cout << sizeof(score) << endl;
	scoreTest(score);
	scorePrint(score,n);
	scoreAdd(score, n, 5);
	scorePrint(score, n);
	scoreAdd(score, n); //这里默认参数使用默认值
	scorePrint(score, n);

	system("pause");
	return 0;
}


5.函数重载

#include <iostream>
#include <Windows.h>

using namespace std;
/*
	函数重载:
		即相同函数名的函数,通过不同的参数个数或参数类型,实现不同的功能
	注意:函数的重载与返回值类型无关
	c语言不支持函数重载
*/

int add(int a, int b) {
	cout << "执行add1" << endl;
	return a + b;
}

int add(int a, int b, int c) {
	cout << "执行add2" << endl;
	return a + b + c;
}

float add(float a,float b) {
	cout << "执行add3" << endl;
	return a + b;
}



int main(void) {
	cout << add(1, 2) << endl;
	cout << add(1, 2, 3) << endl;
	cout << add(1.0f, 2.0f) << endl;//注意:1.0默认是double类型,后边加f标识为float类型

	system("pause");
	return 0;
}


6.函数的栈空间、内联函数和递归函数

6.1 函数的栈空间

当调用一个函数时,就会在栈空间,为这个函数,分配一块内存区域,
这块内存区域,专门给这个函数使用。
这块内存区域,就叫做“栈帧”。

在这里插入图片描述

#include <iostream>
#include <Windows.h>

using namespace std;

/*
	栈空间:
		函数执行时,栈空间会为其变量分配一段连续的内存空间,变量的大小不能超过内存的大小
		否则,函数会因为栈空间溢出而中断程序
	这里定义一个2MB的char数组,程序会因为栈空间溢出而中止
*/

void test1() {
	char buff[1000000]; //2MB 2000000(约等于)1024*1024*2 ,函数在这里执行时会因为栈空间溢出而中断执行
	
	cout << (int)buff[sizeof(buff) - 1] << endl;
}
/*
	通过递归函数引发的栈空间溢出中断
*/
void test2(int n) {
	char buff[1024 * 100];//100K
	printf("%d\n", n);
	printf("buff的地址空间是:%X\n", buff);
	if (n == 1)
	{
		return;
	}
	test2(n - 1);
}

int main(void) {
	//test1();
	test2(3);
	system("pause");
	return 0;
}

6.2 内联函数

通过 inline 关键字 inline void fun(){};
内联函数执行过程中会将调用该函数的地方进行代码替换
使用调用函数的栈空间,从而避免了系统分配栈空间的开销
优点:执行速度快
缺点:程序在后台执行时,会变得臃肿,并且消耗调用函数的栈空间
使用场合:
1.内联函数内代码很简单、执行很快的几条语句
2.某函数的使用频率很高,比如在一个循环中千万次调用


#include <iostream>
#include <Windows.h>

using namespace std;

inline int add(int a ,int b) {
	return a + b;
}

int main(void) {
	/*
		这里调用内联函数,在执行过程中,不在为add分配新的栈空间,而是将 add(3,5)
		替换为3+5,直接使用main函数的栈空间 
	*/
	cout << add(3, 5) << endl;

	system("pause");
	return 0;
}


6.3 递归函数

定义:在函数的内部,直接或者间接的调用自己。
要点:再定义递归函数时,一定要确定一个“结束条件”!!!
使用场合:
处理一些特别复杂的问题,难以直接解决。
但是,可以有办法把这个问题变得更简单(转换成一个更简单的问题)。
注意:递归函数的效率是非常低的

#include <iostream>
#include <Windows.h>

using namespace std;

/*
	递归的思想是把问题拆解为若干与原始问题同样的小问题

*/
/*
	斐波那契数列的递归实现:
		求第n个序列的斐波那契数列的值

		1,1,2,3,5,8,13,21,34...

		输入n

		因为系统为每一个调用的fib函数分配栈空间,当n足够大时,程序的执行效率会很低
*/
int fib(int n) {
	if (n == 1 || n == 2)
	{
		return 1;
	}
	return fib(n - 1) + fib(n - 2);
}

/*
	递归的函数执行过程
		盗梦空间
*/

void manyDream(int n) {
	cout << "进入第" << n << "层梦境..." << endl;
	if (n > 4)
	{
		cout << "退出第" << n << "层梦境" << endl;
		return;
	}
	manyDream(n + 1);
	cout << "退出第" << n << "层梦境..." << endl;
}


int main(void) {


	int n;
	cout << "please enter a num:";
	cin >> n;
	cout << fib(n) << endl;
	n = 1;

	manyDream(n);
	system("pause");
	return 0;
}


7.练习

7.1 封装打印菱形函数

(1)项目需求:
  封装一个可以在控制台通过符号打印菱形的函数
(2)项目实现

#include <iostream>
#include <Windows.h>

using namespace std;

/*
	打印菱形函数:
			输入:
				要打印的菱形行数(奇数),和构成菱形的符号默认为‘*’;
				比如  n = 3; || n = 5
			输出:
					*				   *          line = 0      打印 2个空格   1个*  循环(n/2)+1次
				   ***                ***         line = 1      打印 1个空格	  3个*  循环(n/2)+ i + 1 次
					*				 *****        line = 2      打印 0个空格   5个*  
									  ***         line = 3           1        3		循环 n/2 + (n-i)次
									   *          line = 4           2        1     循环 n/2 + (n-i)次
				通过上述分析,我们把程序分为两段执行,
				当 i(行数,i从0开始) <= n/2 时,打印 n/2 - i个空格,打印2*i + 1个*
				当 i > n/2+1时,i - n/2个空格, [n/2 - (i - n/2)]*2 + 1
*/
void printDiamod(int n , char ch = '*') {
	if (n%2 == 0 || n < 0)
	{
		cout << "请输入正的奇数" << endl;
		return;
	}

	for (int i = 0; i < n; i++)
	{
		if (i <= n/2)
		{
			for (int j = 0; j < n/2 + i + 1; j++)
			{
				if (j < n/2 - i)
				{
					cout << " ";
				}
				else
				{
					cout << ch;
				}
			}
		}
		else
		{
			for (int j = 0; j < n/2 + n - i; j++)
			{
				if (j < i - n/2)
				{
					cout << " ";
				}
				else
				{
					cout << ch;
				}
			}
		}
		cout << endl;
	}
}

int main(void) {
	int n;
	char ch;
	cout << "请输入组成字符:";
	cin >> ch;
	cout << "请输入菱形行数:";
	cin >> n;
	printDiamod(n, ch);

	system("pause");
	return 0;
}

7.2 计算平均工资函数

#include <iostream>
#include <Windows.h>

using namespace std;
/*
	计算员工的平均工资
		输入float数组,返回float平均数
*/
float averageSalary(float salary[], int n) {
	float s = 0;
	for (int i = 0; i < n; i++)
	{
		s += salary[i];
	}
	return s/n;
}
int main(void) {
	//1.
	/*int n;
	char ch;
	cout << "请输入组成字符:";
	cin >> ch;
	cout << "请输入菱形行数:";
	cin >> n;
	printDiamod(n, ch);*/

	//2.
	float salary[3] = { 15000,20000,60000 };//这里会有强制类型转换
	
	printf("%.2f\n", averageSalary(salary, sizeof(salary) / sizeof(salary[1])));

	/*cout.precision(2);
	cout.flags(cout.fixed);
	cout << averageSalary(salary, sizeof(salary) / sizeof(salary[1])) << endl;
	cout.precision(6);
	cout.unsetf(cout.fixed);*/

	system("pause");
	return 0;
}

7.3 不使用递归实现斐波那契函数

#include <iostream>
#include <Windows.h>

using namespace std;


/*
	输出斐波那契数列指定项
*/
int fib(int n) {
	if (n <= 0)
	{
		cout << "请输入正确数值" << endl;
		return 0;
	}
	if (n == 1 || n == 2)
	{
		return 1;
	}
	int index1 = 1, index2 = 1;
	for (int i = 0; i < n-2; i++)
	{
		int tmp = index1 + index2;
		index1 = index2;
		index2 = tmp;
	}
	return index2;

}
int main(void) {
	int n;
	cout << "请输入所求项:";
	cin >> n;
	cout << fib(n) << endl;
	
	system("pause");
	return 0;
}

你好!对于心脏病预测的问题,使用循环神经网络(RNN)是一种常见的方法。RNN适用于处理序列数据,而心电图信号就是一种序列数据。在使用RNN进行心脏病预测时,你可以将心电图信号作为输入序列,然后通过训练RNN模型来预测患者是否患有心脏病。 首先,你需要准备一个合适的数据集,其中包含心电图信号和相应的心脏病标签。可以使用公开的心电图数据集,如PTB数据库或MIT-BIH数据库。然后,你可以对数据进行预处理和特征工程,如数据清洗、滤波、降采样等。 接下来,你可以构建一个RNN模型。RNN模型由一系列循环层组成,每个循环层都会处理一个时间步的输入数据。你可以选择不同类型的RNN单元,如简单循环单元(SimpleRNN)、长短期记忆网络(LSTM)或门控循环单元(GRU)。通过添加适当的全连接层和激活函数,你可以将RNN模型输出映射到二分类问题(有或无心脏病)的结果。 然后,你可以使用训练集对RNN模型进行训练,并使用验证集进行模型调优。在训练过程中,你可以使用适当的损失函数(如交叉熵)和优化算法(如随机梯度下降)来最小化模型的预测误差。 最后,你可以使用测试集对训练好的模型进行评估,并计算模型的性能指标,如准确率、精确率、召回率等。这些指标可以帮助你评估模型的预测能力和泛化能力。 需要注意的是,心脏病预测是一个复杂的医学问题,仅仅使用心电图信号可能不能得到准确的预测结果。通常情况下,还需要结合其他患者的临床信息和医学知识来进行综合评估。因此,在进行心脏病预测时,建议与专业医生合作,并遵循相关的医学准则和规范。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值