目录
项目二、黑客攻击系统-输入账号
为看书困难的小伙伴推荐视频教程:百度网盘
第 1 节 项目需求
项目 1 中, 没有输入账号登录, 就直接显示功能菜单.
应该先让用户输入账号并登录.
第 2 节 项目实现
#include <iostream>
#include <Windows.h>
int main(void) {
char name;
int pwd;
std::cout << "请输入账号:";
std::cin >> name;
std::cout << "请输入密码:";
std::cin >> pwd;
/*
std::cout << "1.网站 404 攻击" << std::endl;
std::cout << "2.网站篡改攻击" << std::endl;
std::cout << "3.网站攻击记录" << std::endl;
std::cout << "4.DNS 攻击" << std::endl;
std::cout << "5.服务器重启攻击" << std::endl;
*/
system("pause");
return 0;
}
注意:该实现存在以下问题,
-
账号名称太简单,只能输入单个字符
-
密码只能是整数,太简单,不安全。
-
密码输入时,不能隐藏
以上问题在项目 3 中解决.
第 3 节 项目精讲
3.1 C++的数据类型
已使用的数据类型: 字符串类型, 整数类型
什么是数据类型?
现实社会中的人, 分成很多”类型”
“物以类聚, 人以群分”
不同类型的人, 思考问题,处理问题的方式都不一样。
计算机中的数据, 也分成很多类型:
int | unsigned int | char |
unsigned char | long | long long |
unsigned long | short | unsigned short |
float | double | 各种指针类型 |
枚举类型 | struct结构类型 | union联合类型 |
bool | string | 类 |
C++ 完全支持 C 语言的各种数据类型。
不同数据类型的区别:
-
表示意义不同
-
占用内存不同
-
表示的范围不同
-
使用方法不同
数据类型使用不当,将导致严重的后果。
-
对于程序员:隐藏 BUG
-
对于系统:隐藏灾难
因数据类型使用不当,产生数据溢出,导致阿丽亚娜 5 型运载火箭自爆
1996 年 6 月 4 日,阿丽亚娜 5 型运载火箭的首次发射点火后,火箭开始偏离路线,最终被逼引爆自毁,整个过程只有短短 30 秒。阿丽亚娜 5 型运载火箭基于前一代 4 型火箭开发。在 4 型火箭系统中,对一个水平速率的测量值使用了 16 位的变量及内存,因为在 4 型火箭系统中反复验证过,这一值不会超过 16 位的变量,而 5 型火箭的开发人员简单复制了这部分程序,而没有对新火箭进行数值的验证,结果发生了致命的数值溢出。发射后这个 64 位带小数点的变量被转换成 16 位不带小数点的变量,引发了一系列的错误,从而影响了火箭上所有的计算机和硬件,瘫痪了整个系统,因而不得不选择自毁,4 亿美金变成一个巨大的烟花。
3.2 构建 IT 大厦的砖块:变量
变量,不是数学中的变量。
为什么要使用变量
程序在运行时,需要保存很多内容常常变化的数据。
比如,射击类游戏中不断变化的“分数”。
世界中的芸芸众生:
程序中的数据:
一个程序运行时,大量数据存储在“变量”中。
数据在大量变量之间“计算”、“交换”。
变量是处理数据的基本实体。
变量是什么
变量,是内存中的一块存储空间,即一小块内存。
变量和数据类型有什么关系?
变量,是一个盒子,盒子里保存了“数据”。
数据又分成很多“类型”(数据类型)。
=> 变量的类型,就是变量中数据的类型。
=> 变量在定义(创建)时,必须先指定它的类型。
【相当于:制作一个盒子时,必须先确认这个盒子是用来装什么的】。
=> 1 个变量只有 1 个类型,而且不能改成其他类型。
变量的定义
定义形式 1:
int x;
int y;
定义形式 2:(不推荐)
int x, y;
定义形式 3:(定义的时候,设置一个初始值)
int x = 100;
代码解读:
int a; //定义了一个变量
a = 100;
内存的存储单位-“字节”
内存的存储单位,是字节。
一个字节,包含 8 位二进制位。
变量名的命名规范
-
只能包含 3 种字符(数字、大/小写字母,下划线)
-
不能以数字开头(即,只能以字母或下划线开头) int 2name; //非法
-
不能和“关键字”同名(c 语言内部已经使用的“名称”),比如类型名 int
变量名的最大长度,C 语言没有规定。
最大长度限制,取决于编译器,一般都在 32 以上。
变量名,最好“顾名思义”,不用使用汉语拼英的简写!
比如:用 name 表示姓名,用 power 表示功率。
命名风格:
1)下划线风格:int student_age; (一般用于变量名、函数名)
2)小驼峰风格:int studentAge; (一般用于变量名、函数名)
3)大驼峰风格:class StudentAge; (一般用于“类名”)
4)全部大写 (一般用于宏):#define MAX_AGE 30
请忘记“匈牙利命名法”(属性+类型+对象描述)
3.3 用于计数的整数类型
原始人,使用结绳计数,这个“数”就是整数
int 类型
使用最多的整数类型
在内存中占 4 个字节
表示范围:- (2 的 31 次方)~2 的 31 次方-1 【正负 21 亿左右】
长整形 long
long 也就是 long int
可用来存储更大的整数。
在 32 位系统上,占 4 个字节,和 int 相同
在 64 位系统上,占 8 个字节【正负 9 百亿亿左右】
长长整形 long long
用来存储整数。
在内存中占 8 字节。
很少使用,仅用于特殊的计算。
短整形 short
用来存储整数。
在内存中占 2 字节。
用于存储小范围的整数
表示范围:- (2 的 15 次方)~2 的 15 次方-1 【正负 3 万多】
---------------------- 分割线 ----------------------
无符号类型, 铁公鸡-概不赊欠-没有负数
unsigned int
unsigned long
unsigned long long
unsigned short
最小值都是 0, 最大值是对应的有符号数的 2 倍。
经典用法:
unsigned short port; //用来表示网络通信的端口号(0-65535)
unsigned int num; //表示编号(0 到四十多亿)
3.4 用于单个字符的数据类型
char
某学员的字母故事.
单个字符:
‘0’ ‘1’ ‘2’ ‘3’ ...... ‘9’
‘a’ ‘b’ ‘c’ ‘d’ ...... ‘z’
‘A’ ‘B’ ‘C’ ‘D’ ...... ‘Z’
‘,’ ‘-’ ‘!’ ‘#’ .......
单个字符常量, 要求用‘’括起来
字符类型 char
一个字节。
char name = ‘a’;
内存示意图:
字符的实际表示:
所有的字符,使用对应的 ASCII 值来存储。
为什么?(因为计算机中只能存储 0 和 1 的组合)
ASCII 码,使用 1 个字节(包含 8 个二进制位,即 8 个 0 和 1 的组合)
比如:‘A’ , 用 0100 0001 来表示, 就是 65
‘B’, 用 0100 0010 来表示, 就是 66
char name = ‘a’;
char name = ‘a’;
等效于:
char name = 97;
char 类型的另一种用法
用来表示小范围的整数(-128 ~ 127)
不过现在开发时,小范围的整数,也常常直接用 int 类型。
实例:
int x = 0;
x = ‘a’ + 1; // 97 + 1
注意:
1 和 ‘1’的区别.
int x = 1;
char y = ‘1’; //49
3.5 用于精确计算的数据类型(浮点型)
需要精确计算的数学、工程应用,用整数类型不合适。
生活中的”敏感数据”
float 类型(单精度浮点类型)
用来存储带小数部分的数据。
在内存中占用 4 个字节
表示范围:-3.4*10^38~+3.4*10^38 (不需记忆)
精度:最长 7 位有效数字(是指 7 位 10 进制位)
float y = 1.123456789;
//精度只能取值到 1.1234568, 在第 7 位(整数部分不算)是四舍五入后的值。
float 类型的存储方式:
符号位:0 代表正数,1 代表负数
阶码: 指数+127
符号位 尾数 * 2 ^ (阶码-127)
转化过程:(了解)
float x = 13.625;
13.625 的转化:
double 类型(双精度浮点类型)
用来存储带小数部分的数据。
8 个字节
具体的存储方式和 float 相似.
表示范围:-1.7*10^308~1.7*10^308(不需记忆)
精度:最长 16 位有效数字(是指 16 位 10 进制位)
double y = 1.12345678901;
浮点类型的常量
带小数的常量默认都是 double 类型
3.14 是 double 类型
3.14f 强制指定是 float 类型
可以用”科学计数法”表示浮点类型的常量
1.75E5 或 1.75 e5
1.75E5 就是 1.75 乘以 10 的 5 次方(100000), 175000.0
注意:
1 是 int 类型的常量
1.0 是 double 类型的常量
浮点数据的输出控制
#include<iostream>
#include<Windows.h>
using namespace std;
int main(void){
double value = 12.3456789;
// 默认精度是 6,所以输出为 12.3457
//(默认情况下,精度是指总的有效数字)
cout << value << endl;
// 把精度修改为 4, 输出 12.35, 对最后一位四舍五入
// 精度修改后,持续有效,直到精度再次被修改
cout.precision(4);
cout << value << endl;
// 使用定点法, 精度变成小数点后面的位数
// 输出 12.3457
cout.flags(cout.fixed);
cout << value << endl;
// 定点法持续有效
// 输出 3.1416
cout << 3.1415926535 << endl;
// 把精度恢复成有效数字位数
cout.unsetf(cout.fixed);
cout << value << endl;//输出 12.35
cout << 3.1415926535 << endl; //输出 3.142
system("pause");
return 0;
}
3.6 向计算机输入数据
当缓冲区为空时,程序才会暂停,让用户输入数据。
输入回车后,数据全部送到输入缓冲区。
#include<iostream>
#include<Windows.h>
int main(void){
char girlType;
int salary;
float height;
std::cout << "请输入您的理想类型:\n A:贤惠型 \n B:泼辣新 \n C: 文艺型 \n D:运动型" << std::endl;
std::cin >> girlType;
std::cout << "请输入您的月收入:" << std::endl;
std::cin >> salary;
std::cout << "请输入您的身高:[单位-米]" << std::endl;
std::cin >> height;
std::cout << "您的理想类型是: " << girlType << std::endl;
std::cout << "您的月收入是: " << salary << "元" << std::endl;
std::cout << "您的身高是: " << height << "米" << std::endl;
system("pause");
return 0;
}
小结:
对于 char, int, float 等基本数据类型, 直接使用 std::cin >> 输入即可.
特别注意:
输出使用 std::cout <<
输入使用 std::cin >>
记忆诀窍:
输入, 需要一个很”尖”的 >> 才能实现插入.
3.7 两种不同的的常量
字面常量
int 类型字面常量:1, 2, 3, 100
long 类型字面常量:200L (或 200l, 建议用大写字母 L)
注意:使用 vs 编译时,默认都是 win32 平台,
所以即使在 64 位系统中,long 也只有 4 个字节
long long 类型字面常量:100000000000LL(一千亿,建议用大写字母 LL)
char 类型字面常量:’a’, ‘b’, ‘X’, ‘-’
float 类型字面常量:3.14f
double 类型字面常量: 3.0 3.14
16 进制常量:
123 = 1x100 + 2x10 + 3x1
0x11 (相当于 17)
以 0x 作为前缀
说明:16 进制
8 进制常量
以 0 作为前缀
011(相当于 9)
说明:16 进制和 8 进制,只是给程序员使用起来更方便,
在计算机中,数据都存储为 2 进制。
字面常量的缺点:
程序的可读性变差。
代码的可维护性差。
符号常量
1)#define 宏定义的符号常量
#define MAX_AGE 35
在编译的预处理阶段,直接把 MAX_AGE 替换为 35
2)const 修饰的符号常量
const int maxAge = 35;
maxAge = 30; //错误!编译失败
注意:const 修饰的符号常量,又叫“只读变量”。
本质上,是一个变量,只是被 const 限制。
3.8 常见错误总结
1.变量名错误
变量名不能使用关键字
int char; //编译失败
变量名不能和函数名同名
int system; //会导致后面不能使用 system 函数
2.变量还没有定义,就直接使用
age = 20;
变量一定要先定义,再使用。
3.变量的输入与使用顺序不当
//以下为错误代码
#include<iostream>
#include<Windows.h>
using namespace std;
int main(void){
int age;
int num;
num = age * 360;
cout << "请输入您的年龄: ";
cin >> age;
cout << "这是您在地球的" << num <<"天" << endl;
system("pause");
return 0;
}
num = age * 360;
计算完字符,num 和 age 没有任何关系!
而不是数学中的理解: num 永远是 age 的 360 倍【不适用于 C、C++】
4.数据输入时,数据的类型不匹配
#include<iostream>
#include<Windows.h>
using namespace std;
int main(void){
int age;
int num;
cout << "请输入您的年龄: ";
cin >> age;
num = age * 360;
cout << "这是您在地球的" << num <<"天" << endl;
system("pause");
return 0;
}
输入的是字母 l 和 0
类型不匹配,此时输入失败,变量的值还是原来的值
说明:
变量如果不做初始化,它的值是不确定的。
良好的编程习惯:变量在定义时,进行初始化:
int age = 0;
5.输入数据时,前面的数据输入错误,导致后面的数据都不能输入
#include <iostream>
#include <Windows.h>
#include <string>
int main(void) {
int a;
int b;
int c;
std::cin >> a >> b >> c;
std::cout << "a=" << a << std::endl;
std::cout << "b=" << b << std::endl;
std::cout << "c=" << c << std::endl;
system("pause");
return 0;
}
解决方案:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
int main(void) {
int a;
int b;
int c;
//std::cin >> a >> b >> c;
std::cout << "请输入 a: ";
std::cin >> a;
if (cin.fail()) { //检查输入时是否发生了错误
cout << "输入错误,应该输入一个整数" << endl;
//清除错误标记,使得后续输入可以正常进行
//但是已经输入的数据还在输入缓冲区
cin.clear();
cin.sync(); //清空输入缓冲区
}
std::cout << "请输入 b: ";
std::cin >> b;
if (cin.fail()) {
cout << "输入错误,应该输入一个整数" << endl;
cin.clear(); //清除错误标记,使得后续输入可以正常进行
cin.sync(); //清空输入缓冲区
}
std::cout << "请输入 c: ";
std::cin >> c;
if (cin.fail()) {
cout << "输入错误,应该输入一个整数" << endl;
cin.clear(); //清除错误标记,使得后续输入可以正常进行
}
std::cout << "a=" << a << std::endl;
std::cout << "b=" << b << std::endl;
std::cout << "c=" << c << std::endl;
system("pause");
return 0;
}
if 语句的具体用法在后面会详细讲解。
更完美的解决方案, 使用 C++的异常(后面会精讲)。
3.9 计算机英语加油站
单词/关键字 | 说明 |
char | character 字符 |
int | integer 整数 |
short | 短的 |
long | 长的 |
unisinged | 无符号的 |
double | 双倍的 |
float | 浮动,浮点数 |
name | 名称,名字 |
password | 密码 |
precision | 精度 |
flags | flag 的复数 |
fixed | 固定的 |
unset | 复原 |
const | 常量 |
The variable 'age' is being used without being initialized. ----------------[变量]---------------------[使用] [没有]------------[初始化] |
第 4 节 项目修炼
4.1 编程思维修炼
第 5 关:
函数的参数可以有不同的类型
hero.moveRight(3);
hero.attack("Brak");
根据不同的函数使用不同类型的参数
函数在定义时,就已经规定了需要使用指定类型的参数。
积木式编程训练
步骤:
-
分析游戏原理
-
上传迷宫角色(包含多个造型)
-
选择背景(太空-Light)
-
设置迷宫的初始状态
为迷宫角色添加代码:
5.为小猫设置初始状态
大小设置为 18 (即 18%)
代码:
6.为小猫添加移动代码
注意复制(Ctrl+c)和粘贴(Ctrl+v)的使用
7.防止小猫撞墙
8.添加出口的老鼠,并设置初始状态
9.判断游戏结束
《略》
参考视频和最后的文件“迷宫.sb3”
4.2 程序员职场修炼:怎样安全度过试用期
学员故事:
-
未能完成项目任务,被辞退
-
独立完成项目任务,仍被连续两次辞退
教训:
-
认清自己的定位,个人包装不宜超过自己实际能力的 30%。
-
积极主动的做事,主动地与直接领导保持有效的沟通
-
快速融入团队。
4.3 程序员逼格提升:逼格初体验-代码风格
程序员的第一印象,不是外表,而是自己的代码风格。
-
命名风格
-
缩进风格
-
注释风格
第 5 节 项目练习
5.1练习 1-数学计算
让用户输入一个圆的半径,计算这个圆的周长和面积,并输出(保留两位小数)
5.2练习 2-无符号数的诡异
分析以下代码:
#include <iostream>
#include <Windows.h>
using namespace std;
int main(void) {
unsigned boyAge;
unsigned girlAge;
unsigned diff;
cout << "美女,多大了?" << endl;
cin >> girlAge; //输入 25
cout << "帅哥,多大了?" << endl;
cin >> boyAge; //输入 22
diff = girlAge - boyAge;
cout << "美女比帅哥大" << diff <<"岁" << endl;
diff = boyAge - girlAge;
cout << "帅哥比美女大" << diff << "岁" << endl;
system("pause");
return 0;
}
执行结果:
说明:unsigned 类型,就是 unsigned int
分析:
在尾部添加如下代码:
unsigned short boyAge2 = boyAge;
unsigned short girlAge2 = girlAge;
unsigned short diff2 = boyAge2 - girlAge2;
cout << "帅哥比美女大" << diff2 << "岁" << endl; //输出 65533
结论:无符号数,不能表示负数!
如果强行用无符号数表示负数,实际存储的是这个负数对应的“补码”
即:该负数 + “模值”:-3 + 65536 = 65533
理解:
为看书困难的小伙伴推荐视频教程:百度网盘