文章目录
前言
本文主要介绍了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;
}