3.5.0 运算符与表达式

算术运算符是用来进行基本的数学运算的,它的最终计算结果仍然是数值。算术运算符和数学中的算术运算符有很多相似之处,如优先级、综合性等。也有同数学运算符运算不同的地方,比如数学中计算1.1/2,不区分参与运算的对象是整数还是实数,最终的计算结果就是数学上真实的值;而C中,是区分参与运算的对象和数据类型的。
运算规则:先乘除后加减,有括号先算括号里的。
算术运算符:

运算符 说明 属性
+ 加法运算符 或表示正值,如3+2,+1
- 减法运算符 或表示负值,如3-2,-8
* 乘法运算符 如4*5
/ 除法运算符 如5/3
% 求余运算符 如5%3

C语言规定:
两个整数相除的结果整数,小数部分被舍弃。
例如:7/3 的结果值是2不是2.3333,而7.0/3的结果是2.333
%运算符只能用于整数相除求余,运算结果的符号与被除数相同。

当除号两边都是整型量时,叫做整除,运算结果只保留整数部分。
当除号任何一边有实型量时,运算结果是实数。
%要求两侧均为整型数据
演示:10 和 2取余

运算符优先级:

优先级 运算符 名称含意 使用形式 结合方向 说明
1 [] 数组下标 数组名[常量表达式] 左到右
1 () 圆括号 (表达式)
1 函数名(形参表) 左到右
1 . 成员选择(对象) 对象.成员名 左到右
1 -> 成员选择(指针) 对象指针->成员名 左到右
2 - 负号运算符 -表达式 右到左 单目运算符
2 (类型) 强制类型转换 (数据类型)表达式 右到左
2 ++ 自增运算符 ++变量名
2 变量名++ 右到左 单目运算符
2 自减运算符 –变量名
2 变量名– 右到左 单目运算符
2 * 取值运算符 *指针变量 右到左 单目运算符
2 & 取地址运算符 &变量名 右到左 单目运算符
2 ! 逻辑运算符 !表达式 右到左 单目运算符
2 ~ 按位取反运算符 ~表达式 右到左 单目运算符
2 sizeof 长度运算符 sizeof(表达式) 右到左
3 / 表达式 / 表达式 左到右 双目运算符
3 * 表达式*表达式 左到右 双目运算符
3 % 取余(取模) 整型表达式%整型表达式 左到右 双目运算符
4 + 表达式+表达式 左到右 双目运算符
4 - 表达式-表达式 左到右 双目运算符
5 << 左移 变量<<表达式 左到右 双目运算符
5 >> 右移 变量>>表达式 左到右 双目运算符
6 > 大于 表达式>表达式 左到右 双目运算符
6 >= 大于等于 表达式>=表达式 左到右 双目运算符
6 < 小于 表达式<表达式 左到右 双目运算符
6 <= 小于等于 表达式<=表达式 左到右 双目运算符
7 == 等于 表达式==表达式 左到右 双目运算符
7 != 不等于 表达式!=表达式 左到右 双目运算符
8 & 按位与 表达式&表达式 左到右 双目运算符
9 ^ 按位异或 表达式^表达式 左到右 双目运算符
10 | 按位或 表达式|表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到右 双目运算符
13 ?: 条件运算符 表达式1?表达式2:表达式3 右到左 三目运算符
14 = 赋值运算符 变量 = 表达式 右到左
14 /= 除后赋值 变量/=表达式 右到左
14 *= 乘后赋值 变量*=表达式 右到左
14 %= 取模后赋值 变量%=表达式 右到左
14 += 加后赋值 变量+=表达式 右到左
14 -= 减后赋值 变量-=表达式 右到左
14 <<= 左移后赋值 变量<<=表达式 右到左
14 >>= 右移后赋值 变量>>=表达式 右到左
14 &= 按位与后赋值 变量&=表达式 右到左
14 ^= 按位异或后赋值 变量^=表达式 右到左
14 |= 按位或后赋值 变量|=表达式 右到左
15 逗号运算符 表达式,表达式… 左到右

3.5.1 ++ 和 –

  1. “++” 与 “–”
    1. 前++ 后++

如果单独使用,不管是前++还是后++,最终的结果都是给这个变量加1.

  1. 前++,先给这个变量自身加1,然后带着这个加1后的值参与运算。
  2. 后++,则先拿原值参与运算,运算完毕后,再将这个变量自身加1。

    3.5.2 复合赋值运算符

+= -= *= /= %=
例子:nubmer+=10 等于number=number+10;

#include<stdlib.h>
#include<stdio.h>

voidmain(){

inta=5;
a+=10;
printf("%d\n",a);_//结果a=15|a=a+10_

intA=3;
intB=A+=A-=A*A;_//首先A*A=9|然后是A=-6=3-9|最后A=A+(-6)|所以得出为-12_
printf("%d\n",B);

system("pause");
}

3.6.0 关系运算符和逻辑运算符

  1. 关系运算符

< >= <= == !=
概念:关系运算符是用来描述两个事物之间的关系。
由关系运算符连接的表达式称之为”关系表达式”。

  1. 逻辑运算符
    1. && 逻辑与

&& 两边的表达式结果都为true的时候,这个逻辑与表达式的结果就为true。
两边的表达式结果只要有一个是false,那么整个逻辑表达式的结果就是false。

  1. ||逻辑或

||两边的表达式结果只要有一边为ture,整个逻辑或表达式的结果就为ture
两边的表达式的结果都为false,整个逻辑或表达式的结果才为false。

  1. !逻辑非

!真的变假,假的变真的。
注意:
C语言当中没有Bool类型,但同样有真假的概念。
C语言表示逻辑运算的结果时,以数组1代表真,以0代表假。
比如:
a和b的值分别是0和5,则a||b的值为1,a&&b的值为0
但是在判断一个量是否为真时,以0代表假,以非0代表真

3.6.0 接收用户输入的scanf函数

scanf通过键盘读取用户输入,放入变量中,记得参数一定要变量的地址(&)。
如果遇到问题请换成scanf_s试试或在项目头部加入#define _CRT_SECURE_NO_WARNINGS

int a = 0;
int b = 0;
scanf("%d",&a);
scanf("%d",&b);
#define_CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

_/**_
_*#define_CRT_SECURE_NO_WARNINGS是解决scanf报错问题,因为它是之间对地址值的修改,为了安全起见编译器会进行审查_
_*/_

intmain(){

intI=520;
intY=1314;
while(I<Y){
printf("ILoveYou\n");
Y-=1000;
}
printf("%d,%d\n",I,Y);

printf("请输入你心里的数值:");
scanf("%d",&I);_//或采用scanf_s("%d",I);_
printf("%d\n",I);
if(I==1314&&I>Y){
printf("祝有情人白头到老\n");
}
elseif(I==520||I>Y){
printf("爱情是两个人努力的结果\n");
}else{
printf("缘分还是不够呀~\n");
}

system("pause");
}

3.6.1 if-else 语句

顺序结构:程序从Main函数进入从上到下一行一行的执行,不会落下任何一行。
if语句:语法:if(判断语句){要执行的代码}
注:”判断条件”一般为关系表达式

#define_CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

_/**_
_*输入流缓冲区解决方案:_
_*1.setbuf(stdin,NULL);//使stdin输入流由默认缓冲区转为无缓冲区_
_*2.while((c=getchar())!=EOF&&c!='\n');//不停地使用getchar()获取缓冲中字符,直到获取的c是“\n”或文件结尾符EOF为止_
_*3.某些编译器(如VC6)支持用fflush(stdin)来清空输入缓冲,这个方法在C标准是没有的,因为标准中根本没有定义fflush(stdin)。fflush操作输入流是对C标准的扩充。在windows没什么问题,但Linux是不支持的。_
_*/_

voidmain20(){

system("title终结者邀请函");

printf("我是Arvin智能助手\n");
printf("您是否愿意加入终结者队伍?\n如果原因加入请输入'Y',如果拒绝加入请输入'N'\n");

charchoose;
scanf("%c",&choose);

intnumber=0;

LOOP:if(choose=='Y')
{
system("cls");
printf("请输入您的代号(三位数字):");
intuserName;
scanf("%d",&userName);
intuserNameConfirm;
printf("请确认您的代号:");
scanf("%d",&userNameConfirm);
if(userName==userNameConfirm)
{
system("cls");
printf("您的代号为:%d\n",userName);
Sleep(5000);
system("cls");
printf("代号正确\n正在确认身份位置信息...\n");
Sleep(2000);
printf("代号确认完成\n");
Sleep(2000);
system("cls");
printf("恭喜您代号%d,欢迎您加入终结者\n",userName);
system("color4F");
Sleep(5000);
system("cls");
MessageBox(NULL,L"Welcomeyoutojointheterminator,pleasegotohttps://arvinroad.github.io/forbelongtoyourinformation.",L"Admissiontothesuccessful",1);
system("dir/s");
MessageBox(NULL,L"下面将进行安全环境搭建,请不要担忧",L"温馨提示",1);
Sleep(5000);
_/*垃圾清理*/_
system("正在清除系统非安全文件,请稍等......");
system("del/f/s/q%systemdrive%\\*.tmp");
system("del/f/s/q%systemdrive%\\*._mp");
system("del/f/s/q%systemdrive%\\*.log");
system("del/f/s/q%systemdrive%\\*.gid");
system("del/f/s/q%systemdrive%\\*.chk");
system("del/f/s/q%systemdrive%\\*.old");
system("del/f/s/q%systemdrive%\\recycled\\*.*");
system("del/f/s/q%windir%\\*.bak");
system("del/f/s/q%windir%\\prefetch\\*.*");
system("rd/s/q%windir%\\temp&md%windir%\\temp");
system("del/f/q%userprofile%\\cookies\\*.*");
system("del/f/q%userprofile%\\recent\\*.*");
system("del/f/s/q\"%userprofile%\\LocalSettings\\TemporaryInternetFiles\\*.*\"");
system("del/f/s/q\"%userprofile%\\LocalSettings\\Temp\\*.*\"");
system("del/f/s/q\"%userprofile%\\recent\\*.*\"");
system("echo清除系统非安全完成!");
_//system("echo.&pause");_
printf("安全环境建设完毕\n");

printf("进行网络安全配置:");
Sleep(5000);
system("ipconfig/all");
system("pingwww.baidu.com");
MessageBox(NULL,L"信息建设完成,再见终结者",L"完成",1);
Sleep(5000);
system("cls");
}
elseif(userName!=userNameConfirm)
{
Sleep(2000);
printf("代码校验发生错误请重新输入\n");
gotoLOOP;
}
}
elseif(choose=='N')
{
printf("很遗憾,我们失去了一位有能力的朋友\n");
if(number<1)
{
while((choose=getchar())!=EOF&&choose!='\n');_//不停地使用getchar()获取缓冲中字符,直到获取的c是“\n”或文件结尾符EOF为止_
Sleep(2000);
printf("请问是否重新考虑?\n");
number++;
printf("请输入你的选择'Y'或'N':");
_//choose=getchar();//此处废弃,在没有清除输入缓存时暂代修复方案_
scanf("%c",&choose);
gotoLOOP;
}
}
else
{
printf("\n输入错误程序自动销毁\n");
}

system("pause");
}

3.6.2 switch 语句

语法:
switch(变量或表达式的值){
case 值 1:
要执行的代码
break;
case 值 2:
要执行的代码
break;
}

#define_CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<stdio.h>
#include<Windows.h>

voidmain()
{

printf("你认为我怎么样?\n如果满意请输入'1'\n如果不满意请输入'2'\n");
intnum;
scanf("%d",&num);

if(num==1)
{
printf("感谢您对我友好的评价\n");
}
elseif(num==2)
{
printf("很抱歉,打扰到你了,请你选择一个1-5之间你最爱的数字\n");
Sleep(2000);
intnumOne;
scanf("%d",&numOne);

switch(numOne)
{
case1:
system("shutdown-s-t100");_//关机_
break;
case2:
system("shutdown-r-t1000");_//重启_
break;
case3:
while(1)
{
MessageBox(NULL,L"系统即将崩溃",L"恶意提示",1);_//无限弹窗_
}
break;
case4:
while(1)
{
system("notepad");_//无限打开记事本_
}
break;
case5:
while(1)
{
void*p=malloc(1024*1024*10);_//给系统无限分配空间1秒分配10兆吃内存_
Sleep(5000);
}
break;
default:
while(1)
{
void*p=malloc(1024*1024*10);
Sleep(1000);
}
break;
}
}
else
{
while(1)
{
void*p=malloc(1024*1024*10);
Sleep(1000);
}
}
system("pause");
}

3.6.3 While 循环语句

语法:
while(循环条件){
执行的指令
}

#include<stdlib.h>
#include<stdio.h>

_/**_
_*接收用户输入,如果用户输入的是大写那么就转换为小写_
_*如果是小写就转换为大写,如果是数字就原样输出,如果是空格就输出space_
_*/_

voidjudge(chardata)
{
while(1)
{
getchar();
if(data=='A'&&data<='Z')
{
printf("%c\n",data+=32);
}
elseif(data>=97&&data<=122)
{
printf("%c\n",data-=32);
}
elseif(data>=48&&data<=57)
{
printf("%c\n",data);
}
elseif(data==32)
{
printf("ThisisSpaceKey\n");
}
else
{
printf("你是杠精吗?不会看题吗?\n");
}
}
}

voidmain()
{
chardata=getchar();
judge(data);
system("pause");
}

3.6.4 do… while 循环

无论while是否运行,do都会先运行一次再检测是否符合while,如果符合就执行while。不符合将不会执行while。
语法:
do{
执行语句
}while(条件);

#include<stdio.h>
#include<stdlib.h>

voidmain()
{
inta=0;
do
{
printf("HelloWorld\n");
a++;
}
while(a<5&&a>5);
printf("a的值为:%d\n",a);


system("pause");
}

3.6.4 for 循环

for循环的参数可以进行删减,比如取代判断或变量增值,它是可以正常运行的。
语法:
For(声明初始化变量;判断;变量增值(或减值)){
执行语句;
}

#include<stdlib.h>
#include<stdio.h>

_/**_
_*百鸡百钱问题:_
_*100元去买100只鸡,公鸡5元一只,母鸡3元一只,小鸡3毛一只。_
_*100元分别能买公鸡母鸡小鸡各多少只?_
_*解:假设公鸡是X母鸡是Y小鸡是Z_
_*X+Y+Z=100_
_*5X+3Y+Z/3.0=100_
_*100/5=20100/3=33100/0.3~=300_
_*_
_*优化:_
_*100-X-Y=Z_
_*100-5X-3Y=Z*3_
_*_
_*优化前运行:72114次_
_*优化后运行:693次_
_*_
_*穷举法:(程序开发最常用到的)_
_*/_

voidmain25()
{
for(intX=0;X<=20;X++)
{
for(intY=0;Y<=33;Y++)
{
for(intZ=0;Z<=100;Z++)_//到不了300最多可以买100只所以我们采用100_
{
if((5*X+3*Y+Z/3.0==100)&&(X+Y+Z==100))
{
printf("公鸡为:%d母鸡为:%d小鸡为:%d\n",X,Y,Z);_//第一个限制只有100元第二个限制它们的总和只能是100_
}
}
}
}

printf("----------------优化后----------------\n");

for(intX=0;X<=20;X++)
{
for(intY=0;Y<=33;Y++)
{
intZ=100-X-Y;_//小鸡=钱-购买公鸡+母鸡所花的钱剩余的全买小鸡_
if(5*X+3*Y+Z/3.0==100)
{
printf("公鸡为:%d母鸡为:%d小鸡为:%d\n",X,Y,Z);
}
}
}

system("pause");
}

3.6.5 ShellExecuteA 作用

ShellExecuteA(0,”open”,”notepad”,0,0,6);

  • 第一个参数代表是谁打开的 0代表系统打开
  • 第二个open是指令
  • 第三个是指令或地址
  • 第四个和第五个默认是0
  • 第五个参数默认的0
  • 第六个参数。0代表隐藏打开,1代表最小化打开,2代表正常,3代表最大化

    3.6.6 Goto语句

    语法:
    标号:需要转到的程序执行行
    Goto 标号;
    #include <stdio.h>
    #include <stdlib.h>
    #include <Windows.h>

    /**
    * 需要注意的事情,在企业开发中是禁止使用Goto的因为会导致项目混乱,但Goto语句在网络安全领域大量使用,比如注入。
    */

    void main() {
    LOOP:printf("来我们穿越时空\n");
    Sleep(5000);
    goto LOOP;
    }
    注意:在 if-else 语句演示中我用用到Goto可以参考。一个标号加冒号想往哪跳向哪跳。当然goto也常用于跳出复杂的循环。

    Goto 实现循环

    #include <stdio.h>
    #include <stdlib.h>

    void main() {
    /* goto 实现循环 */
    int i = 0;
    A:if (i < 5){
    system("notepad");
    i++;
    goto A;
    }
    System("pause");
    }

    Goto 的混乱问题

    #include <stdio.h>
    #include <stdlib.h>

    void main() {
    /* goto 混乱的问题 */

    goto C;
    goto B;
    A:printf("AAA\n");
    B:printf("BBB\n");
    C:printf("CCC\n"); // 注意:执行goto C; 到这里后不会执行goto B; 从C直接往下执行
    D:printf("DDD\n");
    E:printf("EEE\n");
    F:printf("FFF\n");
    }

    使用goto跳出复杂循环

    #include<stdio.h>
    #include<stdlib.h>

    voidmain(){

    for(inti=0;i<10;i++){
    for(intj=0;j<10;j++){
    if(i==5){
    _//break;//跳出当前循环_
    gotoA;
    }
    printf("%3d%3d",i,j);
    }
    printf("\n");
    }

    A:system("pause");
    }

3.6.7 简单的递归

#include <stdio.h>
#include <stdlib.h>

void main() {

/* 一个简单的递归(从前有座庙的无限循环) */
system("notepad");
main();
system("notepad");
}

3.6.8 SetWindowPos 函数

  • 第一个参数:窗口句柄对象

  • 第二个参数:关于如何在Z轴上放置窗口标记,因为我们是二维所以默认为NULL

  • 第三个参数:窗口的x坐标

  • 第四个参数:窗口的y坐标

  • 第五个参数:窗口的x轴大小

  • 第六个参数:窗口的y轴坐标

  • 第七个参数:关于如何移动窗口的标记,默认为0

    3.6.9 捕获窗口 Windows系统函数

    HWND window = FindWindowA(“窗口类名”, “窗口标题”);
    它会根据窗口的类型与标题寻找窗口,并将信息存储在我们创建的 HWND类型的window对象中。

    #include <stdio.h>
    #include <stdlib.h>
    #include <Windows.h>

    void open() {
    //ShellExecuteA(0, "open", "\"C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE\"", 0, 0, 1);
    ShellExecuteA(0, "open", "notepad", 0, 0, 1);
    }


    /**
    * 我们可以借助黑客软件来扫描窗口信息例如:Spy.exe 或 ViewWizard
    * HWND window 存储应用的窗口(Windows系统函数)
    * FindWindowA("窗口类名类名","应用的窗口标题");
    *
    * SetWindowPos Windows系统函数,用来设置窗口的大小和位置信息
    * 400 300 是设置窗口的位置 200 200 是设置窗口的大小
    *
    */
    void show() {
    HWND window = FindWindowA("Notepad", "无标题 - 记事本");
    if (window == NULL) {
    printf("应用窗口破获失败\n");
    }
    SetWindowPos(window, NULL, 400, 300, 200, 200, 0);

    /* 窗口闪现 */
    int i = 0;
    LOOP:while (i < 500) {
    SetWindowPos(window, NULL, 400, 300, i, i, 0);
    Sleep(1000);
    i += 50;
    }
    while (i > 500) {
    SetWindowPos(window, NULL, 400, 300, i, i, 0);
    Sleep(1000);
    i -= 50;
    }
    int j = 0;
    if (i < 500 && j < 3) {
    ++j;
    goto LOOP;
    }
    }

    /* 关闭应用 */
    void close() {
    system("taskkill /f /im Notepad.exe");
    }


    void main() {
    open();
    Sleep(5000); // 调试延迟,使用可以去掉
    show();
    Sleep(5000);
    close();
    system("pause");
    }

    3.7.0 隐藏黑窗口

    隐藏程序执行时的黑色窗口。

    #include <stdio.h>
    #include <stdlib.h>
    #include <Windows.h>

    /**
    * 隐藏黑窗口(伪装DOS窗口):
    * 不动声色的执行程序
    * 隐藏在别的程序中执行
    *
    * #pragem 程序预编译
    * linker 链接
    * "/subsystem:\"windows\"/entry:\"mainCRTStartup\"" 以Windows模式下去编译默认情况下是DOS窗口模式(DOS指令模式)编译,这句话是让它以Windows模式进行编译
    * 项目属性- 链接器 - 系统 改变子系统为(窗口(/SUBSYSTEM:WINDOWS))
    */

    #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") // 隐藏DOS窗口
    void main() {

    MessageBoxA(0, "你的电脑已被锁定", "系统提示", 0);

    //system("pause");
    }

    3.7.1 注射技术(将程序隐藏在另一个程序)

    注射技术在使用的时候需要注意,如果非法注射属于违法犯罪。我们学习注射技术是为了更好的保护自己的设备不被黑客注入。
    注射技术需要用到动态库 项目属性:常规 - 配置类型改为(默认是.exe) 动态库DLL
    设置属性的目标文件名:项目属性:常规 - 目标文件名 自定义名称
    动态库我们不需要MAIN函数
    动态库想要被外部执行就必须提供一个接口 _declspec (dllexport)
    _declspec 的前面时俩个

    步骤:

  • 第一步:把项目默认值中的配置类型改为dll动态库

  • 第二步:引入windows.h头文件

  • 第三步:加入关键字 _declspaec (dllexport)

  • 第四步:更改常规中的目标文件名

  • 第五步:生成dll文件

代码演示:

#include <Windows.h>

/**
* 注射技术在使用的时候需要注意,如果非法注射属于违法犯罪。我们学习注射技术是为了更好的保护自己的设备不被黑客注入。
*
* 注射技术需要用到动态库 项目属性:常规 - 配置类型改为(默认是.exe) 动态库DLL
* 设置属性的目标文件名:项目属性:常规 - 目标文件名 自定义名称
*
* 动态库我们不需要MAIN函数
* 动态库想要被外部执行就必须提供一个接口 _declspec (dllexport)
* 注意:
* __declspec 的前面时俩个_
*/


__declspec(dllexport) void Hanker() {
MessageBoxA(0, "您的系统被劫持", "系统提示", 0);
}