汇编、c语言基础教材 - res.bcdaren.com · 编程达人系列内部教材...
Post on 27-Sep-2019
10 Views
Preview:
TRANSCRIPT
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
1
序 言................................................................................................................................................. 9前 言...............................................................................................................................................11第一章 进制.....................................................................................................................................121.1 进制的定义...............................................................................................................................13
1.1.1【我们为什么要学进制?】...........................................................................................131.1.2【学习进制的障碍】.....................................................................................................131.1.3【进制的定义】.............................................................................................................131.1.4【进制的书写】.............................................................................................................13练习:.......................................................................................................................................15
1.2 进制的运算................................................................................................................................16练习:.......................................................................................................................................17
1.3 认识二进制................................................................................................................................18练习:.......................................................................................................................................20
1.4 数据宽度....................................................................................................................................211.4.1【数据宽度的定义】.....................................................................................................211.4.2【有符号数和无符号数】.............................................................................................221.4.3【数据溢出】.................................................................................................................251.4.4【进制的符号】.............................................................................................................251.4.5【容器的种类】.............................................................................................................25
1.5 原码、反码与补码....................................................................................................................271.5.1【原码、反码、补码的概念】.................................................................................... 28练习:.......................................................................................................................................30
1.6 逻辑运算...................................................................................................................................311.6.1【逻辑运算】.................................................................................................................311.6.2【逻辑运算的具体应用】.............................................................................................33练习:.......................................................................................................................................35
第二章 汇编基础.............................................................................................................................362.1 汇编的学习环境搭建.............................................................................................................37
2.1.1【我们为什么要学习汇编】.........................................................................................372.1.2【简单介绍 16 位、32 位、64 位汇编】.................................................................... 372.1.3【为什么学习 32 位汇编】...........................................................................................382.1.4【win32 汇编】..............................................................................................................382.1.5【这章节能让我们学习到汇编什么深度】................................................................ 382.1.6【配置汇编的学习环境】.............................................................................................38
2.2 寄存器.......................................................................................................................................402.2.1【简单介绍寄存器在处理器中是怎么工作的】........................................................ 402.2.2【处理器中有多少寄存器】.........................................................................................40
2.3 通用寄存器上.........................................................................................................................422.3.1【32 位通用寄存器】....................................................................................................422.3.2【寄存器逻辑结构】.....................................................................................................422.3.3【通用寄存器逻辑结构图】.........................................................................................432.3.4【寄存器有自己的编号】.............................................................................................442.3.5【32 位通用寄存器的指定名称及用途】................................................................... 442.3.6【寄存器能存储数据的最大值】................................................................................ 44
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
2
练习:.......................................................................................................................................452.4 通用寄存器下............................................................................................................................46
2.4.1【DTDebug 软件】..........................................................................................................462.4.2【汇编窗口】.................................................................................................................472.4.3【寄存器窗口】.............................................................................................................472.4.4【MOV 指令】..................................................................................................................482.4.5【通用寄存器对数据的存储】.................................................................................... 51练习:.......................................................................................................................................53
2.5 内存...........................................................................................................................................542.5.1【内存的知识】.............................................................................................................542.5.2【正在运行的程序所占的内存空间】........................................................................ 542.5.3【使用内存】.................................................................................................................542.5.4【内存和寄存器的区别】.............................................................................................56练习:.......................................................................................................................................56
2.6 内存地址的五种形式................................................................................................................592.6.1【内存地址的五种表现形式】.................................................................................... 59练习:.......................................................................................................................................60
2.7 数据存储模式............................................................................................................................602.7.1【存储模式】.................................................................................................................73练习:.......................................................................................................................................74
2.8 常用的汇编指令.......................................................................................................................762.8.1【汇编指令】.................................................................................................................79练习:.......................................................................................................................................80
2.9 内存复制....................................................................................................................................802.9.1【MOVS 指令】................................................................................................................88练习:.......................................................................................................................................89
2.10 堆栈相关指令.......................................................................................................................1052.10.1【堆栈知识点】.........................................................................................................1072.10.2【堆栈的使用】.........................................................................................................107练习:.....................................................................................................................................109
2.11 修改 EIP................................................................................................................................1102.11.1【EIP 寄存器的概念】..............................................................................................1212.11.2【JMP 指令】..............................................................................................................1222.11.3【CALL 指令】............................................................................................................1242.11.4【RETN 指令】............................................................................................................127练习:.....................................................................................................................................128
2.12 汇编眼中的函数...................................................................................................................1302.12.1【函数】.....................................................................................................................131练习:.....................................................................................................................................144
2.13 堆栈传参...............................................................................................................................1452.13.1【参数传递方式】.....................................................................................................145练习:.....................................................................................................................................151
2.14 堆栈平衡...............................................................................................................................1512.14.1【堆栈是什么?】.....................................................................................................154
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
3
2.14.2【堆栈的特点】.........................................................................................................1582.14.3【堆栈平衡】.............................................................................................................159练习:.....................................................................................................................................162
2.15 ESP 寻址................................................................................................................................1632.15.1【什么是 ESP 寻址】.................................................................................................1632.15.2【为什么要用 ESP 寻址】........................................................................................ 164练习:.....................................................................................................................................164
2.16 EBP 寻址................................................................................................................................1652.16.1【什么是 EBP 寻址】.................................................................................................165练习:.....................................................................................................................................173
2.17 JCC 指令................................................................................................................................1742.17.1【什么是 JCC 指令】.................................................................................................1742.17.2【标志寄存器】.........................................................................................................174练习:.....................................................................................................................................201
2.18 汇编总结...............................................................................................................................202第三章 初识 C 语言.......................................................................................................................2033.1 C 语言开发工具介绍..............................................................................................................204
3.1.1【开发工具知识】.......................................................................................................2043.1.2【VC++6.0 操作界面】................................................................................................2043.1.3【创建项目步骤】.......................................................................................................208
3.2 第一个程序 Hello World!...................................................................................................213练习:.....................................................................................................................................215
3.3 程序、编译、注释.................................................................................................................2163.3.1【程序、编译】...........................................................................................................2163.3.2【注释】.......................................................................................................................217练习:.....................................................................................................................................218
3.4 代码解析..................................................................................................................................2193.4.1【固定代码】...............................................................................................................2193.4.2【代码分析】...............................................................................................................219练习:.....................................................................................................................................222
3.5 C 语言使用汇编表示..............................................................................................................2233.5.1【“Hello World!”程序使用汇编表现】................................................................ 223练习:.....................................................................................................................................229
3.6 常见问题.................................................................................................................................2303.6.1【标点符号】...............................................................................................................2303.6.2【大、小写】...............................................................................................................2313.6.3【环境问题】...............................................................................................................2323.6.4【快捷键】...................................................................................................................233
第四章 变量和常量.......................................................................................................................2374.1 输入和输出.............................................................................................................................242
4.1.1【控制台输出】...........................................................................................................2434.1.2【控制台输入】...........................................................................................................2434.1.3【转义字符】...............................................................................................................244练习:.....................................................................................................................................244
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
4
4.2 变量和常量.............................................................................................................................2454.2.1【什么是变量?】.......................................................................................................2454.2.2【变量的声明】...........................................................................................................2464.2.3【变量的命名规则】...................................................................................................2474.2.4【赋值】.......................................................................................................................2474.2.3【常量】.......................................................................................................................2474.2.4【初始化】...................................................................................................................249练习:.....................................................................................................................................250
4.3 数据类型(基本类型)..........................................................................................................2524.3.1【数据类型的知识】...................................................................................................2524.3.2【数据类型的分类】...................................................................................................2534.3.3【整型】.......................................................................................................................2554.3.4【浮点型】...................................................................................................................2704.3.5【char 类型】..............................................................................................................2794.3.6【enum 枚举类型】......................................................................................................283练习:.....................................................................................................................................288
4.4 变量在内存中的分布情况......................................................................................................2974.4.1【变量是放在哪里的】...............................................................................................298
4.5 数据类型转换..........................................................................................................................3004.5.1【自动类型转换规则】...............................................................................................300
4.6 运算符与表达式--理论部分.................................................................................................3004.6.1【赋值运算符】...........................................................................................................3054.6.2【算术运算符】...........................................................................................................3094.6.3【关系运算符】...........................................................................................................3104.6.4【逻辑运算符】...........................................................................................................3144.6.5【位运算符】...............................................................................................................3144.6.6【优先级与结合顺序】...............................................................................................316练习:.....................................................................................................................................316
第五章 语句...................................................................................................................................3175.1 if 语句....................................................................................................................................317
5.1.1【if 语句语法】..........................................................................................................332练习:.....................................................................................................................................332
5.2 switch 语句............................................................................................................................3555.2.1【switch 形式 1】.......................................................................................................355练习:.....................................................................................................................................356
5.3 for 语句..................................................................................................................................3585.3.1【for 语句语法形式】................................................................................................3585.3.2【for 语句表现形式】................................................................................................3655.3.3【循环语句的几种退出方式】.................................................................................. 372练习: ...................................................................................................................................375
5.4 while 语句 do while 语句..................................................................................................3775.4.1【while 语句】............................................................................................................3775.4.2【do while 语句】.....................................................................................................383练习:.....................................................................................................................................387
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
5
5.5 goto 语句................................................................................................................................3885.5.1【goto 语句语法】......................................................................................................388练习:.....................................................................................................................................391
5.6 语句综合实战..........................................................................................................................392第六章 数组...................................................................................................................................3996.1 初始数组.................................................................................................................................400
6.1.1【数组的概念】...........................................................................................................4006.1.2【数组的语法格式】...................................................................................................4006.1.3【数组的命名】...........................................................................................................4006.1.4【数组的用途】...........................................................................................................4006.1.5【数组的初始化】.......................................................................................................4056.1.6【获取数组大小】.......................................................................................................405练习:.....................................................................................................................................406
6.2 数组使用实例与反汇编.........................................................................................................4076.2.1【访问数组】...............................................................................................................4076.2.3【数组实例】...............................................................................................................4126.2.4【数组元素的删除和插入】...................................................................................... 417练习:.....................................................................................................................................422
6.3 多维数组..................................................................................................................................4266.3.1【二维数组定义】.......................................................................................................4266.3.2【二维数组实例使用】...............................................................................................4286.3.3【多维数组】...............................................................................................................437练习:.....................................................................................................................................440
6.4 字符.........................................................................................................................................4416.4.1【什么是字符?】.......................................................................................................444
6.5 字符数组..................................................................................................................................4546.5.1【字符数组】...............................................................................................................4546.5.2【字符数组反汇编】...................................................................................................4596.5.3【字符数组实例】.......................................................................................................461练习:.....................................................................................................................................464
第七章 函数...................................................................................................................................4787.1 什么是函数..............................................................................................................................479
7.1.1【什么是函数】...........................................................................................................490练习:.....................................................................................................................................490
7.2 局部变量和全局变量..............................................................................................................4927.2.1【什么是局部变量】...................................................................................................4947.2.2【什么是全局变量】...................................................................................................4957.2.3【还有一种情况:自己有的决不向上要】.............................................................. 496练习:.....................................................................................................................................497
7.3 堆栈图解析生命周期..............................................................................................................5007.3.1【局部变量存放在哪里?】...................................................................................... 5007.3.2【全局变量存放在哪里?】...................................................................................... 5217.3.3【全局变量引发的事故】...........................................................................................5267.3.4【函数的参数内存分布情况】.................................................................................. 533
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
6
练习:.....................................................................................................................................537第八章 结构体...............................................................................................................................5398.1 结构体概念.............................................................................................................................539
8.1.1【结构体概念】...........................................................................................................5408.1.2【结构体内存分部】...................................................................................................540练习:.....................................................................................................................................553
8.2 字节对齐.................................................................................................................................554练习:.....................................................................................................................................556
第九章 指针...................................................................................................................................5679.1 带星号类型特性.....................................................................................................................569
练习:.....................................................................................................................................5709.2 &符号使用...............................................................................................................................582
9.2.1【类型转换】...............................................................................................................5869.2.2【&符号使用】.............................................................................................................5909.2.3【带“*”类型的特征探测:求值】........................................................................ 596练习:.....................................................................................................................................597
9.3 指针与数组..............................................................................................................................5989.3.1【初识指针与数组】...................................................................................................6009.3.2【指针加减操作】.......................................................................................................6049.3.3【指针与数组转换】...................................................................................................6089.3.4【实例代码】...............................................................................................................609练习:.....................................................................................................................................611
9.4 指针与函数..............................................................................................................................6129.4.1【指针作为函数的参数】...........................................................................................6199.4.2【数组作为函数的参数】...........................................................................................6199.4.3【指针作为函数的返回值】...................................................................................... 624练习:.....................................................................................................................................627
9.5 指针与字符串.........................................................................................................................6299.5.1【字符串回顾】...........................................................................................................6309.5.2【常见字符串操作】...................................................................................................630练习:.....................................................................................................................................633
9.6 指针与结构体.........................................................................................................................6399.6.1【探测++、--、+整数、-整数】.............................................................................. 6419.6.2【通过结构体指针读取、修改】.............................................................................. 6419.6.3【实例】.......................................................................................................................642练习:.....................................................................................................................................646
9.7 多维指针..................................................................................................................................6489.7.1【*()与[]的互换表示】.............................................................................................6489.7.2【数组指针进阶】.......................................................................................................652练习:.....................................................................................................................................653
9.8 调用约定..................................................................................................................................6559.8.1【函数调用约定】.......................................................................................................655
9.9 野指针、void、const...........................................................................................................6599.9.1【野指针】...................................................................................................................659
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
7
9.9.2【void 指针】..............................................................................................................6609.9.3【const 指针】............................................................................................................661
9.10 动态内存分配.......................................................................................................................6629.10.1【#define 宏定义】..................................................................................................6639.10.2【内存分配与释放】.................................................................................................6639.10.3【内存泄漏】.............................................................................................................666练习:.....................................................................................................................................670
9.11 链表的概念............................................................................................................................6719.11.1【什么是链表】.........................................................................................................6729.11.2【无头链表的操作】.................................................................................................672练习:.....................................................................................................................................673
9.12 有头链表................................................................................................................................6799.12.1【有头链表的概念】.................................................................................................6809.12.2【有头链表的操作】.................................................................................................680练习:.....................................................................................................................................683
第十章 文件...................................................................................................................................69210.1 认识文件................................................................................................................................693
10.1.1【什么是文件?】.....................................................................................................69410.1.1【文件处理】.............................................................................................................694练习:.....................................................................................................................................695
10.2 保存、读取数据....................................................................................................................69710.2.1【保存数据】.............................................................................................................698练习:.....................................................................................................................................698
10.3 文件的随机访问....................................................................................................................707练习:.....................................................................................................................................708
10.4 多文件项目生成....................................................................................................................710第十一章 PE项目..........................................................................................................................71111.1 PE项目需求文档..................................................................................................................71411.2 PE 文件..................................................................................................................................71511.3 PE 项目实现..........................................................................................................................716附录 A:VMWare 虚拟机安装设置教程...........................................................................................725附录 B:ASCII 码...........................................................................................................................733附录 C:代码规范.............................................................................................................................752附录 D:常见库函数......................................................................................................................757<assert.h>库函数............................................................................................................................759<float.h>库函数.............................................................................................................................. 760<limits.h>库函数.............................................................................................................................761<math.h>......................................................................................................................................... 762<stdio.h>..........................................................................................................................................765<stdlib.h>.........................................................................................................................................770<string.h>.........................................................................................................................................773<time.h>.......................................................................................................................................... 775头文件.............................................................................................................................................777预处理器.........................................................................................................................................780
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
8
附录 E:流程图..............................................................................................................................786附录 F:9.6 节课后练习代码........................................................................................................789课后练习 1代码.............................................................................................................................790课后练习 2代码.............................................................................................................................798
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
9
前 言
本书作为编程达人系列汇编\C 语言教材的第一本入门教材,讲述的内容是进制、汇编
基础、C语言基础语法。本书并没有像市面上流行的 C 语言相关书籍那样一味的注重语法知
识,本书更倾向于像一本学习笔记,教给读者怎么去学习一门语言,为什么会是这样,怎样
去思考并解决问题。书中例举了近 300 个的例题和 600 多个图示,150 多道练习,一步一步
的演示和证明,带领读者顺利入门。
仅仅熟练掌握语法还是远远不够的,下一步的计划是继续完善入门教材,单独编写一本
入门的实战项目练习。通过大量的项目实战和代码堆积,训练编程思维,真正掌握好汇编和
C语言。这样就需要我们学习并掌握更多的知识,比如 Win32、MFC、网络编程、QT、数据库、
数据结构、COM、STL、PE、硬编码等。如果想学习更底层的知识,还需要学习 Windows 内核、
ARM 汇编、Android 内核、Linux 等。这些知识在编程达人平台上有详细的学习路线、视频、
课件、练习和代码,遇到不懂的问题也会有一对一的答疑服务。
本书写作方式:
进制部分:基本语法+例题理解。
汇编部分:指令的基本用法+上机实验+一步步操作截图+总结;
C语言部分:基本语法+示例代码+反汇编解说+一步步操作截图+总结+实战项目。
本书读者对象:
本书将列三类人员为目标读者:
(1)、汇编、C 语言零基础入门;
(2)、希望学习底层基础知识;
(3)、软件逆向入门
本书的学习方法:(1)、认真思考;
(2)、勤于动手;
(3)、相互交流;
由于时间紧、任务重,本书还有很多不够完善的地方,难免会存在一些错误,请读者们
批评指正。错误反馈请发邮件:1753578662@qq.com。也可以通过编程达人平台客服反馈。
致谢
感谢我的父母、哥哥、嫂子对我的全力支持。
感谢封面制作者张雪的无偿支持。
感谢编程达人王 Sir 提供一次非常难得的机遇,感谢诸位老师和同事的热情帮助。感谢
众多读者的关爱。祝大家早日跨入超级程序员的行列。
李娜
2018年 5月 21日
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
10
2.10 堆栈相关指令
本节必须掌握的知识点:
堆栈相关知识
堆栈的使用
掌握 PUSH 指令、POP 指令的格式、功能
本节介绍堆栈相关的知识,在介绍之前,我们回顾一下 DTDebug.exe 界面,首先打开
DTDebug.exe 软件,将飞鸽软件拖到 DTDebug.exe 软件中,如图 2-10-1 所示,DTDebug.exe 界面包括汇编窗口、寄存器窗口、内存窗口、堆栈窗口,本节主要介绍堆栈窗口和寄存器窗口
中的两个寄存器,这两个寄存器分别为 ESP、EBP。
2.10.1【堆栈知识点】
我们知道每个应用程序都有独立的 4GB 内存空间,是不是当前运行的应用程序拥有的
4GB 内存空间都可以使用哪?当然不是,虽然说名义上有 4GB 内存空间,但是在你真正要
用某一块内存时,一定要向操作系统申请,换句话说你要告诉操作系统,我们把这个过程称
为内存申请。
不同的语言,在申请内存时写法是不同的,但他们的本质是相同的,都是申请内存。至
于怎么申请,怎么实现,由于我们当前的进度还没有介绍到 C 语言,所以就不介绍了。
堆栈就是一块内存,操作系统启动时已经分配好的供程序使用的。在这里说明一下,本
节介绍的堆栈与数据结构中的堆栈无关。为什么要有堆栈?堆栈是程序执行过程中必须使用
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
11
的一块内存,任何一个程序需要用到的关键数据、临时数据等,都会在堆栈中有一定的体现,
我们可以把堆栈看成程序的心脏。
看图 2-10-1 堆栈窗口中的内存,都是已经向操作系统申请过的。那么我们怎么知道申
请了多少堆栈哪?看图 2-10-1 寄存器窗口中有 FS 位,它对应的数据是 0x00272000,在DTDebug.exe软件中找到命令窗口,输入 dd 0x00272000,如图 2-10-2 所示:
点击键盘上的 Enter 键,如图 2-10-3 所示:
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
12
在内存窗口中,内存地址 0x00272004 对应的数据是 0x001A0000 (Top of thread's stack),内存地址 0x00272008 对应的数据是 0x0019D000 (Bottom of thread's stack)。这就是操作系
统为我们分配的堆栈地址,从 0x0019D000 到 0x001A0000,堆栈窗口中的内存地址就在这个
范围的。不同的系统分配的大小会有差异。由于堆栈是操作系统专门给程序用的,程序在执
行过程中必须使用堆栈,所以它又可以看做是一块特殊的内存。
堆栈窗口中的内存地址是从高内存地址到低内存地址用的,也就是从内存地址
0x001A0000 开始使用到内存地址 0x0019D000 结束,如果用完了,就会报错,提示堆栈溢出。
那我们怎么知道当前程序堆栈使用到哪里了?比如图 2-10-3 汇编窗口中,当前程序停在了
0x77068E34,我们看寄存器窗口中,ESP 寄存器存储的数据为 0x0019FFF0,则 0x0019FFF0 为当
前程序堆栈使用到的地方。那么从内存地址 0x001A0000 到内存地址 0x0019FFF0 都已经被使
用过了如图 2-10-4 所示:
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
13
为什么是 ESP 寄存器哪?为什么不是别的寄存器?在之前我们介绍过,32 位汇编中 8个通用寄存器都有各自的用途,ESP 为栈指针,用于指向栈的栈顶,也就是说当前使用到的
存储数据的内存地址。有指向栈顶的指针,肯定有指向栈底的指针,那就是 ESB 寄存器,ESP为帧指针,指向当前活动记录的底部。
我们知道了堆栈的知识,那我们该怎么使用堆栈哪?接下来介绍堆栈的使用
2.10.2【堆栈的使用】
我们当前程序执行到某个阶段时,中间会产生大量的数据,而这些数据将会暂时保存
在堆栈中。如果我们现在要使用堆栈,假如有临时数据 0x00000001 和临时数据 0x00000002,我们怎么能让这些临时数据暂时保存在堆栈中哪?如图 2-10-4 寄存器窗口中 ESP 存储的当
前数据为 0x0019FFF0,说明堆栈已经使用到了内存地址为 0x0019FFF0,临时数据只能存储在内
存地址 0x0019FFEC 往上的地方。知道存储在哪了,接下来就是写汇编指令将临时数据保存
在堆栈中了。
我们可以用已经学过的指令:
第一步:输入指令,如图 2-10-5 所示:
MOV DWORD PTR DS:[0x0019FFEC],0x00000001MOV DWORD PTR DS:[0x0019FFE8],0x00000002
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
15
两次按 F8 执行后,临时数据 0x00000001 和临时数据 0x00000002 都已经暂时存储在了
堆栈中。但 ESP 寄存器存储的数据并没有发生变化,这时我们要告诉堆栈当前已经使用到内
存地址为 0x0019FFE8 的地方,若不告诉堆栈,则下一次再存储数据时可能会覆盖掉之前存
储的临时数据,那么该如何告诉堆栈哪?
第一步:输入指令,如图 2-10-8 所示:
SUB ESP,4SUB ESP,4因为向堆栈中写入了 2 次数据且堆栈中的数据是从高地址到低地址,所以将 esp 的值减
少 8 个字节,也可写成 SUB ESP,8。
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
16
第二步:按 F8 执行并观察 ESP 寄存器存储的数据变化及堆栈窗口的变化,如图 2-10-9、2-10-10 所示:
图 2-10-9 堆栈窗口中的黑色定位光标显示在了内存地址 0x0019FFEC 中,而 ESP 存储的
数据为 0x0019FFEC,说明堆栈已经记录了数据 0x00000001。我们接着按 F8 观察。
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
17
图 2-10-10 堆栈窗口中的黑色定位光标显示在了内存地址 0x0019FFE8 中,而 ESP 存储的
数据为 0x0019FFE8,说明堆栈已经记录了数据 0x00000002。我们以后再使用数据时,可以先提升栈顶,再存入数据。比如再向堆栈中存入临时数据
0x33333333,我们先提升栈顶, 在输入数据。
第一步:先提升栈顶,如图 2-10-11,ESP 存储的数据为 0x0019FFE8。SUB ESP,4
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
18
第二步:按 F8 执行并观察数据变化如图 2-10-12 所示。
图 2-10-12 堆栈窗口中的黑色定位光标显示在了内存地址 0x0019FFE4 中,而 ESP 存储的
数据为 0x0019FFE4,说明堆栈已经提升了。
第三步:向堆栈中写入数据,如图 2-10-13 所示,当前 ESP 存储的数据为 0x0019FFE4,内存地址 0x0019FFE4 存储的数据为 0x00000000。
MOV DWORD PTR SS:[ESP],0x33333333
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
19
第四步:按 F8 执行并观察数据变化,如图 2-10-14。
图 2-10-14 寄存器窗口中 ESP 存储的数据为 0x0019FFE4,内存地址 0x0019FFE4 存储的
数据为 0x33333333。假如我们存储的临时数据 0x00000001、0x00000002 和 0x33333333,使用后不需要再用,
那我们该如何释放被临时数据占用的内存哪?由于我们使用的内存地址总是栈顶指针 ESP的相对位置,所以我们只要修改 ESP 的值,就可以将这一块内存释放出来供下次使用,所以
用完这 3 个临时数据后,我们恢复原来的堆栈。
第一步:由于是存放了 3 个临时数据,输入指令,如图 2-10-15 所示。
ADD ESP,4ADD ESP,4ADD ESP,4或者 ADD ESP,0xC
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
20
图 2-10-15 中,ESP 存储的数据为 0x0019FFE4,当前栈顶为内存地址 0x0019FFE4。第二步:按 F8 单步执行并观察堆栈窗口中黑色光标区域栈顶的变动,如图 2-10-16 所示。
图 2-10-16 中,堆栈窗口中的黑色定位光标区域为内存地址 0x0019FFF0,寄存器窗口中
ESP 存储的数据为 0x0019FFF0,所以成功恢复到一开始没有存储临时数据的内存地址。
大家肯定看到图 2-10-16 中我们存储的临时数据还存在,这里我们已经恢复了栈顶,至
于之前存储的临时数据对我们来说毫无影响了,下次存储临时数据时可以直接覆盖,对我们
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
21
调试程序没有影响。
【拓展:我们在使用 C 语言或其他语言时,为什么要给局部变量赋初始值,原因就在这,
如果没有初始化,只是申请变量空间,那么这里面的值就会影响我们的结果。】
以上我们是用基础指令来演示堆栈变化,汇编语言还给我们提供了一些简化指令。
【PUSH 指令】
PUSH 指令它的功能是:
1、向堆栈中压入数据
2、修改栈顶指针 ESP 寄存器的值
PUSH 指令的格式:
PUSH r32PUSH r16PUSH m16PUSH m32PUSH imm我们 push 立即数的时候,默认为 4 个字节,这里不能使用 8 位寄存器或者内存。
例:
我们动手做实验,输入以下指令,如图 2-10-17 所示:
PUSH 0x33333333
第二步:按 F8 执行并观察数据变化,如图 2-10-18 所示。
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
22
看图 2-10-18寄存器窗口 ESP存储的数据为 0x0019FFEC,堆栈窗口中黑色定位光标区域为
内存地址 0x0019FFEC,为当前栈顶,内存地址 0x0019FFEC 存储的数据正是我们压入的数据
0x33333333,所以可以总结出,PUSH 0x33333333 这条指令相当于:
1、MOV DWORD PTR SS:[ESP],0x333333332、SUB ESP,0x33333333
学汇编我们不要记汇编的格式,要真正掌握它的工作原理,当我们能用其他的指令实现
相同的功能才能真正学会了汇编。接下来我们学习另一个堆栈指令,我们记住它的功能,并
能用其它指令代替,才能算掌握。
【POP 指令】
POP 指令功能:
1、将栈顶数据存储到寄存器/内存
2、修改栈顶指针 ESP 寄存器的值
POP 指令格式:
POP r32POP r16POP m16POP m32POP 指令是将栈顶指针指向的数据取出,所以必须要有一个容器去接收 POP 指令弹出
来的值,所以 POP 后面不能是立即数
例:
我们动手做实验,输入以下指令,如图 2-10-19 所示,当前 ESP 存储的数据为 0x009FFF0,内存地址 0x009FFF0 存储的数据为 0x11111111,也是栈顶:
POP ECX
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
23
第二步:按 F8 执行后观察数据变化,如图 2-10-20 所示:
看图 2-10-20 寄存器窗口中,ESP 存储的数据为 0x0019FFF4,堆栈窗口中黑色定位光标区
域为内存地址 0x0019FFF4,为当前栈顶,ECX 存储的数据正是我们取出的数据 0x11111111,所以可以总结出,POP 这条指令相当于:
1、MOV DWORD PTR SS:[ESP]2、ADD ESP,4
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
24
总结:PUSH、POP 是堆栈相关的指令,PUSH 表示将数据压入堆栈中,同时栈顶提升相
应宽度的字节,POP 表示将栈顶的数据取出来放到某个容器里,同时栈顶减少相应宽度的字
节。
下一节介绍修改 EIP 指令。
练习:
1、使用 3 种方式实现:PUSH ECX2、使用 3 种方式实现:POP ECX3、使用 3 种方式实现:PUSH ESP4、使用 3 种方式实现:POP ESP
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
25
9.1 带星号类型特性
本节必须掌握的知识点:
熟练使用带“*”的类型
掌握带“*”类型的七大特征
指针是什么?很多人说,指针就是地址,那这么说的人肯定是对指针有所了解,他们这
么说也不能说全错,我只能在这里说:“他们并没有真正学会指针,如果想学好指针,请先
忘记指针就是地址这句话。”
在介绍指针之前,我们先复习一下我们所接触的数据类型:char、short、int、float、
double、数组、结构体等,那么本节将继续补充一个新的数据类型,那就是在我们之前所学
的数据类型后面加一个星号“*”,该类型与 char、short、int、float、double、数组、结
构体等类型一样,没有什么特殊之处。
例如:int* x; int *y;有这两种写法。为了代码的可读性,笔者建议大家使用
int* x;这种写法。这种变量类型叫什么哪?我们暂且叫带星号类型,待我们揭开它面
纱的那一刻,我会告诉大家它的真是名称。
那么肯定会有人问,可以在变量后写一颗“*”,那可以写两颗“*”吗?可以。那可以
写三颗“*”吗?可以。那可以写四颗“*”吗?可以.那可以写十颗“*”吗?可以。具体是
什么含义,请耐心往下看。
我们将带着如下几个问题进行学习:【在今后学习其他语言时,一定要带入以下问题去
学习。】
1、带“*”类型的特征探测:宽度;
2、带“*”类型的特征探测:声明;
3、带“*”类型的特征探测:赋值;
4、带“*”类型的特征探测:++ 、--;
5、带“*”类型的特征探测:加上/减去 一个整数;
6、带“*”类型的特征探测:求差值;
7、带“*”类型的特征探测:比较。
【注意:只要我写的这 7个特征探测里面没有的特性,说明带“*”的变量就没有该操
作。】
对于一个变量来说,最重要的一个特征就是数据的宽度,如何探测某个变量的宽度?请
大家思考,先介绍如何声明一个变量。
9.1.1【特征探测:声明】
如何声明一个 char、short、int、float、double、数组、结构体类型的变量?
char c;
short s;
int n;
float f;
double d;
char str[24];
struct Student
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
26
{
int level;
char name[20];
};
Student st;
以上是 char、short、int、float、double、数组、结构体类型的声明。
如何声明带“*”类型的声明哪?
推荐写法:
char* c;
short* s;
int* n;
float* f;
double* d;
char* str[24];
struct Student
{
int level;
char name[20];
};
Student* st;
如何声明带“**”类型的声明哪?
推荐写法:
char** c;
short** s;
int** n;
Float** f;
Double** d;
char** str[24];
struct Student
{
int level;
char name[20];
};
Student** st;
不推荐写法:
char *c;
short *s;
int *n;
float *f;
double *d;
char *str[24];
struct Student
{
int level;
char name[20];
};
Student *st;
不推荐写法:
char **c;
short **s;
int **n;
float **f;
double **d;
char **str[24];
struct Student
{
int level;
char name[20];
};
Student **st;
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
27
如何声明带“***”类型的声明哪?
推荐写法:
char*** c;
short*** s;
int*** n;
Float*** f;
Double*** d;
char*** str[24];
struct Student
{
int level;
char name[20];
};
Student*** st;
以上是 char、short、int、float、double、数组、结构体类型中带“*”、“**”、“***”
的声明。
【特征探测:赋值】
char c ;
c = 1;
short s ;
s = 2;
int n;
n = 4;
接下来看“*”怎么赋值哪?
char* c ;
c = 1;
这样赋值对吗?我们拿到 VC++6.0 下看看。
图 9-1-1
看图 9-1-1 按 F7 编译,编译器报错了,cannot convert from ‘const int ‘ to ‘char
*’,不能从 const int 转换到 char *。那我们该怎么给带“*”类型赋值哪?需要使用标
不推荐写法:
char ***c;
short ***s;
int ***n;
float ***f;
double ***d;
char ***str[24];
struct Student
{
int level;
char name[20];
};
Student ***st;
其实 C 语言中标准写法是:
char c;
c =(char)1;
而 char c; c = 1;是简化版的,这样写编译器
一样可以编译过,是因为现在编译器比较智能
了。
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
28
准写法,不能使用简化写法。
char* c ;
c =(char*) 1;
图 9-1-2
那么带“**”“***”……“********”的类型该怎么赋值哪?其实与带“*”类型赋值
是一样的,如下图 9-1-3 所示:
图 9-1-3带“*”类型声明、赋值都介绍完了,不知道读者还记不记得,我一开始遗留了一个问
题:“如何探测某个变量的宽度?”认真思考、动手能力强的读者肯定已经自己有了答案。
这里我们使用 sizeof 来检测带“*”类型的宽度。
【特征探测:宽度】
#include <stdio.h>
示例代码 CH09_1_1
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
29
#include <windows.h>
int main(void)
{
char* c;
c = (char*)1; //一颗“*”赋值
printf("%d\n",sizeof(c));//检测一颗“*”的大小
char** c2;
c2 = (char**)2; //两颗“**”赋值
printf("%d\n",sizeof(c2));//检测两颗“**”的大小
char*** c3;
c3 = (char***)3;//三颗“***”赋值
printf("%d\n",sizeof(c3));//检测三颗“***”的大小
char**** c4;
c4 = (char****)4;//四颗“****”赋值
printf("%d\n",sizeof(c4));//检测四颗“****”的大小
system("pause");
return 0;
}
运行结果:
图 9-1-4
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
30
看到图 9-1-4 显示的运行结果,有没有什么疑惑哪?我相信肯定有,因为 char 类型是 1字节,而 char* 类型是 4 个字节,按这种规律,那么 char** 应该是 8 个字节,char*** 应
该是 12 个字节,而且是结果都是 4。这里要好好的说一下了,char 后面不管带几个“*”它
的宽度永远是 4 个字节。我们知道结构体有字节对齐的概念,那么我们论证一下带“*”的
是不是 4 个字节。
定义这两个结构体测试:
struct TypeName{
char* st1;char** st2;char*** st3;int**** st4;
};struct TypeName2{
char st1;char st2;char st3;int st4;
};struct TypeName* type ={0};printf("%d\n",sizeof(type));//检测带“*”结构体的大小
struct TypeName type1 ={0};printf("%d\n",sizeof(type1));//检测结构体的大小
struct TypeName2 type2 ={0};printf("%d\n",sizeof(type2));//检测结构体的大小
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
31
图 9-1-5我们看图 9-1-5 中,发现 struct TypeName* type ={0};type 被 sizeof 检测到的大小为 4,
而我们在 struct TypeName 结构体里面定义的是 char* st1;char** st2;char*** st3;int**** st4;正常情况下应该是 char* st1;占 4 个字节;char** st2;占 4 个字节;char*** st3;占 4 个字
节;int**** st4;占 4 个字节;一共是 16 个字节才对。这里要搞清楚喽,它的定义形式是:
struct TypeName* type ={0};看到没,是“TypeName*”这种带“*”的类型,所以它的大小只
占 4 个字节。
struct TypeName type1 ={0};这个正是我们分析的占 16 个字节。
struct TypeName2 type2 ={0};它占 8 个字节,就不会感到奇怪了,该结构体考虑到了字
节对齐的概念。
我们正向代码已经分析完了,我们看下它的反汇编是怎么个形式。
20: struct TypeName* type ={0};
0040D388 mov dword ptr [ebp-4],0
我们们定义的是结构体带“*”类型,可是我们在反汇编中并没有看见“*”的体现
21: printf("%d\n",sizeof(type));//检测带“*”结构体的大小
0040D38F push 4
这里是直接将 4压入栈//这就是检测出 type 的大小
0040D391 push offset string "%d\n%d\n%d\n%d\n" (004210f0)
0040D396 call printf (00401070)
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
32
0040D39B add esp,8
22: struct TypeName type1 ={0};
0040D39E mov dword ptr [ebp-14h],0
0040D3A5 xor eax,eax
0040D3A7 mov dword ptr [ebp-10h],eax
0040D3AA mov dword ptr [ebp-0Ch],eax
0040D3AD mov dword ptr [ebp-8],eax
以上一块连续的内存操作,我们知道可以对一块连续的内存操作有数组、结构体。
23: printf("%d\n",sizeof(type1));//检测结构体的大小
0040D3B0 push 10h
0040D3B2 push offset string "%d\n%d\n%d\n%d\n" (004210f0)
0040D3B7 call printf (00401070)
0040D3BC add esp,8
24: struct TypeName2 type2 ={0};
0040D3BF mov byte ptr [ebp-1Ch],0
0040D3C3 xor ecx,ecx
0040D3C5 mov dword ptr [ebp-1Bh],ecx
0040D3C8 mov word ptr [ebp-17h],cx
0040D3CC mov byte ptr [ebp-15h],cl
这一块是对一块连续不等宽的内存进行操作,那么这段极有可能是使用结构体定义的。
xor ecx,ecx 这是清零操作,那么而 ecx 里存储的数据是 0,所以[ebp-1Bh]、[ebp-17h]、
[ebp-15h]存储的都是 0,只不过数据宽度不一样。
25: printf("%d\n",sizeof(type2));//检测结构体的大小
0040D3CF push 8
0040D3D1 push offset string "%d\n%d\n%d\n%d\n" (004210f0)
0040D3D6 call printf (00401070)
0040D3DB add esp,8
26: char* c;
27: c = (char*)1; //一颗“*”赋值
0040D3DE mov dword ptr [ebp-20h],1
这里是把 1移动到[ebp-0x20],看上面一行代码是以带“*”的类型定义的,但反汇编
并没有给我们显示这个“*”。
28: printf("%d\n",sizeof(c));//检测一颗“*”的大小
0040D3E5 push 4
0040D3E7 push offset string "%d\n%d\n%d\n%d\n" (004210f0)
0040D3EC call printf (00401070)
0040D3F1 add esp,8
29: char** c2;
30: c2 = (char**)2; //两颗“**”赋值
0040D3F4 mov dword ptr [ebp-24h],2
这里是把 2移动到[ebp-0x24],看上面一行代码是以带“**”的类型定义的,但反汇编
并没有给我们显示这个“**”。
31: printf("%d\n",sizeof(c2));//检测两颗“**”的大小
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
33
0040D3FB push 4
0040D3FD push offset string "%d\n%d\n%d\n%d\n" (004210f0)
0040D402 call printf (00401070)
0040D407 add esp,8
32: char*** c3;
33: c3 = (char***)3;//三颗“***”赋值
0040D40A mov dword ptr [ebp-28h],3
这里是把 3移动到[ebp-0x28],看上面一行代码是以带“***”的类型定义的,但反汇
编并没有给我们显示这个“***”。
34: printf("%d\n",sizeof(c3));//检测三颗“***”的大小
0040D411 push 4
0040D413 push offset string "%d\n%d\n%d\n%d\n" (004210f0)
0040D418 call printf (00401070)
0040D41D add esp,8
35: char**** c4;
36: c4 = (char****)4;//四颗“****”赋值
0040D420 mov dword ptr [ebp-2Ch],4
这里是把 4移动到[ebp-0x2C],看上面一行代码是以带“****”的类型定义的,但反汇
编并没有给我们显示这个“****”。
37: printf("%d\n",sizeof(c4));//检测四颗“****”的大小
0040D427 push 4
0040D429 push offset string "%d\n%d\n%d\n%d\n" (004210f0)
0040D42E call printf (00401070)
0040D433 add esp,8
看到以上反汇编,可以推论,带“*”类型的定义在反汇编中并没有体现,与其它数据
类型定义并无明显差别。
总结:
1、带有*的变量类型的标准写法:变量类型* 变量名;
2、任何类型都可以带* 加上*以后是新的类型;
3、*可以是任意多个;
4、带*类型的变量赋值时只能使用“标准写法”;
5、带*类型的变量宽度永远是 4 字节、无论类型是什么,无论有几个*。
【特征探测:++、--】
下面我们来探讨第四个特征:++、--的操作。
首先我们先看 char、short、int 类型对++的操作。
#include <stdio.h>
int main(void)
{
char a ;
short b ;
int c ;
示例代码 CH09_1_2
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
34
a = 100;
b = 100;
c = 100;
a++;
b++;
c++;
printf("%d %d %d",a,b,c);
return 0;
}
运行结果:
图 9-1-6
我相信上面的代码,读者朋友都能看懂,若看不懂请从 C语言篇开始看。
那么我们看下带“*”的类型对++操作是什么结果。
#include <stdio.h>
int main(void)
{
char* a;
short* b;
int* c;
示例代码 CH09_1_3
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
35
a = (char*)100;
b = (short*)100;
c = (int*)100;
a++;
b++;
c++;
printf("%d %d %d",a,b,c);
return 0;
}
运行结果:
图 9-1-7
看图 9-1-7 中,输出的结果是:101、102、104。对结果是不是感到很意外?
char* a;
short* b;
int* c;
同时对它们赋值为:100,同时做++操做,结果却大相径庭。这是为什么哪?在这里暂
且不透露为什么,请读者自己思考一下,这是为什么?先别着急写答案,也许答案并不是你
想的那么简单。
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
36
接着看下带“**”、“***”类型对++的操作:
#include <stdio.h>
int main(void)
{
char** a;
short** b;
int** c;
char*** a2;
short*** b2;
int*** c2;
a = (char**)100;
b = (short**)100;
c = (int**)100;
a2 = (char***)100;
b2 = (short***)100;
c2 = (int***)100;
a++;
b++;
c++;
a2++;
b2++;
c2++;
printf("a=%d b=%d c=%d\n",a,b,c);
printf("a2=%d b2=%d c2=%d\n",a2,b2,c2);
return 0;
}
示例代码 CH09_1_4
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
37
运行结果:
图 9-1-8
看图 9-1-8 中,运行结果:a = 104,b = 104, c = 104, a2 = 104, b2 = 104,c2 = 104。
看到这个结果是不是感到很意外?我们结合图 9-1-7、9-1-8 一起看,为什么同样是带“*”
的、同样是做++操作,为什么会有不一样的结果呢?别着急,且听我慢慢道来。
我们知道带“*”的类型的数据宽度是 4字节,那么这个++操作与“*”号前定义的数据
类型有关系,比如 char* a;这个就是定义了一个 char 星的类型,在没有“*”号时,char
类型是数据宽度是 1字节,加上“*”就是 4 字节。接着我们看++操作,如果带”*”的类
型做++操作,首先需要先砍掉一颗星,其次加上砍掉一颗星后的宽度。那么我们就是一下,
这样对不对:
char* a;
short* b;
int* c;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a++;
b++;
c++;
a = (char*)100;我们遵循带“*”类型++操作法则:首先砍掉一颗星,在加上砍掉一颗
星的宽度。char* 砍掉一颗星变成 char,char 的宽度是 1 字节,所以 a++ = 100+1 = 101;
我们看图 9-1-7 运行结果,a= 101,那么一个结果对了,并不一定是对有可能存在巧合,那
么我们继续往下分析。short* 砍掉一颗星变成 short,short 的宽度是 2 字节,所以 c++ =
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
38
100+2 = 102;int* 砍掉一颗星变成 int,int 的宽度是 4字节,所以 c++ = 100+4 = 104;
带一颗“*”类型进行++操作,是遵循:首先需要先砍掉一颗星,其次加上砍掉一颗星
后的宽度,这个规律的。那我们接着看对“**”、“***”类型的++操作。
char** a;
short** b;
int** c;
char*** a2;
short*** b2;
int*** c2;
a = (char**)100;
b = (short**)100;
c = (int**)100;
a2 = (char***)100;
b2 = (short***)100;
c2 = (int***)100;
a++;
b++;
c++;
a2++;
b2++;
c2++;
char** 砍掉一颗星变成 char*,char*的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 a++ = 100+4 = 104;
short** 砍掉一颗星变成 short*,short*的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 b++ = 100+4 = 104;
int** 砍掉一颗星变成 int*,int*的宽度是 4 字节(不管有几颗星,只要带“*”那么
它的宽度就是 4字节),所以 c++ = 100+4 = 104;
char*** 砍掉一颗星变成 char**,char**的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 a2++ = 100+4 = 104;
short*** 砍掉一颗星变成 short**,short**的宽度是 4 字节(不管有几颗星,只要带
“*”那么它的宽度就是 4 字节),所以 b2++ = 100+4 = 104;
int*** 砍掉一颗星变成 int**,int**的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 c2++ = 100+4 = 104;
以下代码请自己分析:
#include <stdio.h>
int main(void)
{
char* a;
short* b;
int* c;
char** a1;
short** b1;
示例代码 CH09_1_5
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
39
int** c1;
char*** a2;
short*** b2;
int*** c2;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a1 = (char**)100;
b1 = (short**)100;
c1 = (int**)100;
a2 = (char***)100;
b2 = (short***)100;
c2 = (int***)100;
++a;
++b;
++c;
++a1;
++b1;
++c1;
++a2;
++b2;
++c2;
printf("a=%d b=%d c=%d\n",a,b,c);
printf("a1=%d b1=%d c1=%d\n",a1,b1,c1);
printf("a2=%d b2=%d c2=%d\n",a2,b2,c2);
return 0;
}
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
40
运行结果:
图 9-1-9
接下来看带“*”的类型对--操作的结果:
#include <stdio.h>
int main(void)
{
char* a;
short* b;
int* c;
char** a1;
示例代码 CH09_1_6
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
41
short** b1;
int** c1;
char*** a2;
short*** b2;
int*** c2;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a1 = (char**)100;
b1 = (short**)100;
c1 = (int**)100;
a2 = (char***)100;
b2 = (short***)100;
c2 = (int***)100;
a--;
b--;
c--;
a1--;
b1--;
c1--;
a2--;
b2--;
c2--;
printf("a=%d b=%d c=%d\n",a,b,c);
printf("a1=%d b1=%d c1=%d\n",a1,b1,c1);
printf("a2=%d b2=%d c2=%d\n",a2,b2,c2);
return 0;
}
分析:
char* 砍掉一颗星变成 char,char*的宽度是 1字节,所以 a-- = 100-1 = 99;
short* 砍掉一颗星变成 short,short 的宽度是 2 字节,所以 b-- = 100-2 = 98;
int* 砍掉一颗星变成 int,int 的宽度是 4字节,所以 c-- = 100-4 = 96;
char** 砍掉一颗星变成 char*,char*的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 a1-- = 100-4 = 96;
short** 砍掉一颗星变成 short*,short*的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 b1-- = 100-4 = 96;
int** 砍掉一颗星变成 int*,int*的宽度是 4 字节(不管有几颗星,只要带“*”那么
它的宽度就是 4字节),所以 c1-- = 100-4 = 96;
char*** 砍掉一颗星变成 char**,char**的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 a2-- = 100-4 = 96;
short*** 砍掉一颗星变成 short**,short**的宽度是 4 字节(不管有几颗星,只要带
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
42
“*”那么它的宽度就是 4 字节),所以 b2-- = 100-4 = 96;
int*** 砍掉一颗星变成 int**,int**的宽度是 4 字节(不管有几颗星,只要带“*”
那么它的宽度就是 4字节),所以 c2-- = 100-4 = 96;
运行结果:
图 9-1-10
总结:
1、不带“*”类型的变量,++或者-- 都是进行+1 或者-1 的操作;
2、带“*”类型的变量,可是进行++ 或者 --的操作;
3、带“*”类型的变量,++ 或者 --操作,其遵循规则:首先需要先砍掉一颗星,其次
加上或减去砍掉一颗星后的宽度。
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
43
【特征探测:加上/减去 一个整数】
#include <stdio.h>
int main(void)
{
char* a;
short* b;
int* c;
char** a1;
short** b1;
int** c1;
char*** a2;
short*** b2;
int*** c2;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a1 = (char**)100;
b1 = (short**)100;
c1 = (int**)100;
a2 = (char***)100;
b2 = (short***)100;
c2 = (int***)100;
a = a + 5 ;
b = b + 5 ;
c = c + 5 ;
a1 = a1 + 5 ;
b1 = b1 + 5 ;
c1 = c1 + 5 ;
a2 = a2 + 5 ;
b2 = b2 + 5 ;
c2 = c2 + 5 ;
printf("a=%d b=%d c=%d\n",a,b,c);
printf("a1=%d b1=%d c1=%d\n",a1,b1,c1);
printf("a2=%d b2=%d c2=%d\n",a2,b2,c2);
return 0;
}
在输入结果之前,请读者思考一下,是不是砍掉一颗星之后的宽度+100 再+5 哪?如果
是这样想的,那就错了,我们看运行结果,会让你大吃一惊的。
示例代码 CH09_1_7
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
44
运行结果:
图 9-1-11
解析:看到图 9-1-11 显示出来的结果,是不是感到很意外,我来帮大家解开这层面纱,
首先先看 char* a;带“*”的类型进行做加一个整数操作时,它会先砍掉一颗星,然后看宽
度,再使用宽度乘它要加的整数,比如 char* a;a = (char*)100;a = a + 5;char* a; 先
把 char* a 的类型砍掉一颗“*”,砍完后它的数据宽度是 1 字节,它要加的整数是 5,所以
会使用宽度乘 5,1*5=5,再加上 100,最后结果为 105。
short* b;b = (short*)100;b = b + 5;short* b; 先把 short* b 的类型砍掉一颗“*”,
砍完后它的数据宽度是 2字节,它要加的整数是 5,所以会使用宽度乘 5,2*5=10,再加上
100,最后结果为 110。
int* c;c = (int*)100;c = c + 5;int* c; 先把 int* c 的类型砍掉一颗“*”,砍完后
它的数据宽度是 4 字节,它要加的整数是 5,所以会使用宽度乘 5,4*5=20,再加上 100,
最后结果为 120。
char** a1;a1 = (char**)100;a1 = a1 + 5;char** a1; 先把 char** a1 的类型砍掉一
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
45
颗“*”,砍完后它的数据宽度是 4字节,它要加的整数是 5,所以会使用宽度乘 5,4*5=20,
再加上 100,最后结果为 120。
short** b1;b1 = (short**)100;b1 = b1 + 5;short** b1; 先把 short** b1 的类型砍
掉一颗“*”,砍完后它的数据宽度是 4字节,它要加的整数是 5,所以会使用宽度乘 5,4*5=20,
再加上 100,最后结果为 120。
int** c1;c1 = (int**)100;c1 = c1 + 5;int** c1; 先把 int** c1 的类型砍掉一颗“*”,
砍完后它的数据宽度是 4字节,它要加的整数是 5,所以会使用宽度乘 5,4*5=20,再加上
100,最后结果为 120。
char*** a2;a2 = (char***)100;a2 = a2 + 5;char*** a2; 先把 char*** a2 的类型砍
掉一颗“*”,砍完后它的数据宽度是 4字节,它要加的整数是 5,所以会使用宽度乘 5,4*5=20,
再加上 100,最后结果为 120。
Short*** b2;b2 = (short***)100;b2 = b2 + 5;short** b2; 先把 short*** b2 的类
型砍掉一颗“*”,砍完后它的数据宽度是 4字节,它要加的整数是 5,所以会使用宽度乘 5,
4*5=20,再加上 100,最后结果为 120。
int*** c2;c2 = (int***)100;c2 = c2 + 5;int*** c2; 先把 int*** c2 的类型砍掉一
颗“*”,砍完后它的数据宽度是 4字节,它要加的整数是 5,所以会使用宽度乘 5,4*5=20,
再加上 100,最后结果为 120。
#include <stdio.h>
int main(void)
{
char* a;
short* b;
int* c;
char** a1;
short** b1;
int** c1;
char*** a2;
short*** b2;
int*** c2;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a1 = (char**)100;
b1 = (short**)100;
c1 = (int**)100;
a2 = (char***)100;
b2 = (short***)100;
c2 = (int***)100;
a = a - 5 ;
b = b - 5 ;
c = c - 5 ;
a1 = a1 - 5 ;
示例代码 CH09_1_8
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
46
b1 = b1 - 5 ;
c1 = c1 - 5 ;
a2 = a2 - 5 ;
b2 = b2 - 5 ;
c2 = c2 - 5 ;
printf("a=%d b=%d c=%d\n",a,b,c);
printf("a1=%d b1=%d c1=%d\n",a1,b1,c1);
printf("a2=%d b2=%d c2=%d\n",a2,b2,c2);
return 0;
}
运行结果:
图 9-1-12
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
47
char* a;a = (char*)100;a = a - 5;char* a; 先把 char* a 的类型砍掉一颗“*”,砍
完后它的数据宽度是 1字节,它要减的整数是 5,所以会使用宽度乘 5,1*5=5,100 再减 5,
最后结果为 95。
short* b;b = (short*)100;b = b - 5;short* b; 先把 short* b 的类型砍掉一颗“*”,
砍完后它的数据宽度是 2 字节,它要减的整数是 5,所以会使用宽度乘 5,2*5=10,100 再
减 10,最后结果为 90。
int* c;c = (int*)100;c = c - 5;int* c; 先把 int* c 的类型砍掉一颗“*”,砍完后
它的数据宽度是 4 字节,它要减的整数是 5,所以会使用宽度乘 5,4*5=20,100 再减 20,
最后结果为 80。
char** a1;a1 = (char**)100;a1 = a1 - 5;char** a1; 先把 char** a1 的类型砍掉一
颗“*”,砍完后它的数据宽度是 4字节,它要减的整数是 5,所以会使用宽度乘 5,4*5=20,
再加上 100,最后结果为 120。
short** b1;b1 = (short**)100;b1 = b1 - 5;short** b1; 先把 short** b1 的类型砍
掉一颗“*”,砍完后它的数据宽度是 4字节,它要减的整数是 5,所以会使用宽度乘 5,4*5=20,
100 再减 20,最后结果为 80。
int** c1;c1 = (int**)100;c1 = c1 - 5;int** c1; 先把 int** c1 的类型砍掉一颗“*”,
砍完后它的数据宽度是 4 字节,它要减的整数是 5,所以会使用宽度乘 5,4*5=20,100 再
减 20,最后结果为 80。
char*** a2;a2 = (char***)100;a2 = a2 - 5;char*** a2; 先把 char*** a2 的类型砍
掉一颗“*”,砍完后它的数据宽度是 4字节,它要减的整数是 5,所以会使用宽度乘 5,4*5=20,
100 再减 20,最后结果为 80。
short*** b2;b2 = (short***)100;b2 = b2 - 5;short** b2; 先把 short*** b2 的类
型砍掉一颗“*”,砍完后它的数据宽度是 4字节,它要减的整数是 5,所以会使用宽度乘 5,
4*5=20,100 再减 20,最后结果为 80。
int*** c2;c2 = (int***)100;c2 = c2 - 5;int*** c2; 先把 int*** c2 的类型砍掉一
颗“*”,砍完后它的数据宽度是 4字节,它要的减整数是 5,所以会使用宽度乘 5,4*5=20,
100 再减 20,最后结果为 80。
总结:
1、带*类型的变量可以加、减一个整数,但不能乘或者除;
2、带*类型变量与其他整数相加或者相减时:
带*类型变量 + N = 带*类型变量 + N*(去掉一个*后类型的宽度);
带*类型变量 - N = 带*类型变量 - N*(去掉一个*后类型的宽度)。
【特征探测:求差值】
#include <stdio.h>
int main(void)
{
char* c;
char* c1;
char** c2;
char** c3;
char*** c4;
示例代码 CH09_1_9
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
48
char*** c5;
c = (char*)100;
c1 = (char*)200;
c2 = (char**)100;
c3 = (char**)200;
c4 = (char***)100;
c5 = (char***)200;
int x = c1-c;
int y = c3-c2;
int z = c5-c4;
printf("x=%d\n",x);
printf("y=%d\n",y);
printf("z=%d\n",z);
return 0;
}
运行结果:
图 9-1-13
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
49
解析:
1、c 与 c1 是同一类型的,所以可以做减法,如果使用 c2 减从 c1,编译器会给你扔出
一个错误。所以只有同一类型才可以计算差值 。
2、解说这个结果是怎么来的,先看 c1 - c =100;首先明确它们都是 char*类型的,其
次它们都是先相减,最后在除以砍掉一颗星的宽度,c1 = 200; c = 100;c1-c=100,得到 100
之后在除以它们数据类型砍掉一颗星的宽度,char*砍掉一颗星是 char,所以数据宽度是 1
字节,100 除 1=100;
c3 - c2 =25;首先明确它们都是 char**类型的,其次它们都是先相减,最后在除以砍
掉一颗星的宽度,c3 = 200; c2 = 100;c1-c=100,得到 100 之后在除以它们数据类型砍掉一
颗星的宽度,char**砍掉一颗星是 char*,所以数据宽度是 4字节,100 除 4=25;
c5- c4 =25;首先明确它们都是 char***类型的,其次它们都是先相减,最后在除以砍
掉一颗星的宽度,c3 = 200; c2 = 100;c1-c=100,得到 100 之后在除以它们数据类型砍掉一
颗星的宽度,char***砍掉一颗星是 char**,所以数据宽度是 4 字节,100 除 4=25;
总结:
1、两个类型相同的带*类型的变量可以进行减法操作;
2、相减的结果要除以砍掉一个*的数据的宽度。
【特征探测:比较】
#include <stdio.h>
int main(void)
{
char* c;
char* c1;
char** c2;
char** c3;
char*** c4;
char*** c5;
c = (char*)100;
c1 = (char*)200;
c2 = (char**)100;
c3 = (char**)200;
if(c<c1)
{
printf("%d\n",c1);
}else
{
printf("%d\n",c1);
}
if(c3<c2)
示例代码 CH09_1_10
编程达人系列内部教材
有问题,找达人!编程达人!官网:www.bcdaren.com
50
{
printf("%d\n",c3);
}else
{
printf("%d\n",c2);
}
return 0;
}
运行结果:
图 9-1-14
分析:这段代码主要是为了让读者明白,带“*”类型的是可以做比较的,必须是同一
类型的,如果不是同一类型的是不可以做比较的。如果读者切换到该程序的反汇编模式下查
看,编译器是当作无符号数进行比较的。
top related