一、前言
从本文开始,我们就开始进入实战,让你切实体会到学习C/C++的乐趣所在。
不知道大家有没有看过关于黑客题材的电影,如果没有,可以给大家推荐一部电影,名为:《我是谁:没有绝对安全的系统》
这部电影有多经典呢?你现在在网上所能搜索到的很大部分黑客图片都来自这部电影!
里面主角就是一位电脑天才,同时也是一名黑客大佬,拿起电脑,几行代码一敲,电脑屏幕字符闪动,就入侵成功了
现实中这可能吗?虽然很难,但确实是可能的。
本文将带你了解那屏幕字符飞速滚动的原理,以及为什么能够只敲几行代码,就能入侵系统。
二、项目准备
还是老规矩,在原解决方案中,新建一个空的控制台项目,名为day3
,并设置为启动项目。
具体步骤在第二章,如果忘了,请回头看一下,然后给新项目添加一个源文件main.cpp
:
三、码代码
在main.cpp
文件中添加上基本程序结构:
#include<iostream>
int main() {
}
在第二章讲函数的时候我提到过,main
本身也是一个函数,上面这种属于其中的无参数写法。
但其实它还有一种带参数的写法:
#include<iostream>
int main(int argc,char** argv) {
}
当然,argc
与argv
这两个名字只是变量名,是可以自己随便改的,真正重要的是这两个参数的类型。
接下来就说说这两个参数的含义:
argc
:外部传进来的参数个数argv
:外部传入的参数
当你看到argv
这个参数类型的时候可能有点懵,char*
我知道,就指针嘛,存地址的,那char **
是什么鬼?
这时候我们就要把char*
看成一个整体了,前面说过,char*
在C/C++中一般用来表示一个字符串。
那在字符串类型后面再加一个*
是什么意思?那自然就是字符串指针了!
稍稍理解一下就是,一块连续的内存,每块内存都存放的地址,而每个地址指向的位置都是一个字符串的首地址。
和char*
一样,char**
也是可以看作各个字符串连着的,通过地址递增就可以访问下一个。
听上去是不是和数组很像?
前面说过,其实数组的变量名本身就是指针,更加方便的方式是用下标来访问,访问方法:
argv[0]; //访问第一个字符串,等价于*(argv+0)
argv[1]; //访问第二个字符串,等价于*(argv+1)
//类比单个字符串 char* c="yushi-"; c[0]='y',c[1]='s',等价于*(c+0)='y',*(c+1)='s'
//共有argc个字符串
为了切实体验到这两个参数的作用,我们可以用for循环将它们打印出来:
#include<iostream>
int main(int argc,char** argv) {
std::cout << "一共有" << argc << "个参数\n";
for (int i = 0; i < argc; i++)
{
std::cout << "第" << i + 1 << "个参数为:" << argv[i] << "\n";
}
}
结果为:
可以看到,默认情况下,好像就只有一个参数,而且这个参数应该是个路径,进入这个目录看看?
看这名字,不就是我们刚建立的项目名嘛,后缀为.exe
,说明应该是可以执行的,点击试试?
是不是发现有什么东西一闪而过了?多点几次,你应该能大概看出来,那就是个黑窗口。
那么能不能让它别这么快消失呢?
办法肯定是有的,前面提到过,main
函数是系统调用的地方,从后面的{}
开始。看到一句就执行一句,执行完了怎么办?那当然就退出了。
所以我们让它别执行完就行了,改为以下代码:
#include<iostream>
int main(int argc,char** argv) {
std::cout << "一共有" << argc << "个参数\n";
for (int i = 0; i < argc; i++)
{
std::cout << "第" << i + 1 << "个参数为:" << argv[i] << "\n";
}
while (true) {
}
}
讲while
循环的时候说过,当后面判断语句为真就会循环,这里直接设置为true
,就会陷入死循环,这样main
函数就不会退出了!
先在VS中点击运行一下试试:
如果运行结束了,VS一般都会打印一些东西,而这次除了我们写的输出代码外,就根本没有VS的输出,这说明我们的程序还在运行着。
关掉,重新来到刚才的文件夹中点击day3.exe
文件试试!
现在是不是就可以了!那么接下来如何添加我们自定义的参数呢?
答案就是我们先打开控制台,用控制台运行它,直接在当前文件夹中,输入cmd
,按Enter
:
就从控制台进入该文件夹了,可什么是控制台呢?
简单来说,控制台就是一种只能显示字符的平台,它可以让你通过敲入命令来操作你的电脑,这和你用鼠标操作电脑是一样的,可以参考这篇文章进一步学习:程序员必懂常识。
而之所以输入的是cmd
而不是其它,是因为cmd
是控制台程序的名称:
前面显示的就是你当前所在的文件夹,然后输入命令dir
查看当前目录有哪些文件:
可以看到,和从文件管理器中看到的是一样的,其中day3.exe
就在其中,然后我们输入day3.exe
试一试:
看,是不是运行了!只是路径发送了一点变化而已!
但由于我们写的是死循环,程序自己停不下来,这时候就可以按Ctrl+C
强制它停止:
然后我们就可以输入参数了!
day3.exe https://www.kucoding.com C++实战入门到精通
结果为:
就可以看到,程序将我们输入在.exe
文件的后面字符串,当作参数传给了我们的软件,而且这些参数是以空格分割的!
这样我们就可以在程序中得到这些参数,然后我们根据这些参数执行对应的动作就行了!改代码为如下内容:
#include<iostream>
int main(int argc,char** argv) {
if (argc == 1) { //没有输入参数
std::cout << "请输入参数!";
}
else if (argc == 2) { //只输入了一个参数
std::cout << "参数不足!";
}
else if (argc == 3) { //输入两个参数
if (strcmp(argv[1], "attack") == 0) { //比较我们输入的第一个参数是否和attack字符串相同,相同则该函数返回0
for (int i = 0; i < 5; i++) { //循环输出5次话
std::cout << "Attacking " << argv[2] << " "; //输出一个字符串
for (int j = 0; j <= i; j++) { //在上面的字符串后面打印i+1个点
std::cout << ".";
}
std::cout << "\n"; //换行
int num = 10000000; //让程序卡在这里一会
while (num) {
num--;
};
}
std::cout << "Successful attack!\n"; //输出结束字符串
}
else { //输入的第一个参数不是attack
std::cout << "不存在该命令\n";
}
}
else { //输出超过两个参数
std::cout << "参数过多!";
}
}
由于我们当前过于基础,很多东西都还没有讲到,所以暂时也只能这样过一过瘾。
上面的代码我写了很详细的注释,但考虑到结构还是比较复杂,各种嵌套,所以我还是给大家理一理。
首先看最外面的结构,就是一个多次判断的if
语句,用来判断我们输入了几个参数:
if (argc == 1) {
std::cout << "请输入参数!"; //没有输出参数
}
else if (argc == 2) { //只输入了一个参数
std::cout << "参数不足!";
}
else if (argc == 3) { //输入两个参数
}
else { //输出超过两个参数
std::cout << "参数过多!";
}
注意:程序自己有默认的一个参数,上面提到过,所以只有将argc-1
,才是我们输入的参数个数。
当没有输入参数,或者只输入一个参数时,进行提示,输出字符串。
当我们输入的参数个数超过2个时(也就是argc
大于3),同样输出字符串进行提示。
只有输入的参数为2时,我们才开始工作:
if (strcmp(argv[1], "attack") == 0) { //比较我们输入的第一个参数是否和attack字符串相同,相同则该函数返回0
}
else { //输入的第一个参数不是attack
std::cout << "不存在该命令\n";
}
这里调用了一个函数,strcmp
,str(string)
表示字符串,cmp(compare)
表示比较,结合起来的意思是:字符串之间的比较。
一般来说,函数名字要写成该函数要实现功能的英文简写,和这个函数一样,方便我们见名知意!
这里给大家说一下,可能你早就发现了,当你在VS里面敲代码时,旁边总会弹出来一个列表:
其实这就是VS这种IDE高级的地方,能够帮助你联想你想输入的东西,当你输入函数名的前几个字符时,所有符合的函数都会给你列出来。
你就可以用上下箭头按键,来选择你需要的函数,然后按Enter
键,就会帮你补全了,是不是特别方便!
但你很快会发现一个弊端,就是如果我鼠标点击了别处,再点击回来,提示就消失了,而且就算你接着敲也不出提示。
这时候你就只能把刚才的内容删除掉,然后重新敲才会出提示,就会非常不便!