汇编、C语言基础教材 - res.bcdaren.com · 编程达人系列内部教材...

52
编程达人系列内部教材 有问题,找达人!编程达人!官网:www.bcdaren.com [汇编、C 语言基础教材] [编程达人系列教材] [昆山爱达人信息技术有限公司]

Transcript of 汇编、C语言基础教材 - res.bcdaren.com · 编程达人系列内部教材...

编程达人系列内部教材

有问题,找达人!编程达人!官网:www.bcdaren.com

[汇编、C 语言基础教材]

[编程达人系列教材]

[昆山爱达人信息技术有限公司]

编程达人系列内部教材

有问题,找达人!编程达人!官网: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)、相互交流;

由于时间紧、任务重,本书还有很多不够完善的地方,难免会存在一些错误,请读者们

批评指正。错误反馈请发邮件:[email protected]。也可以通过编程达人平台客服反馈。

致谢

感谢我的父母、哥哥、嫂子对我的全力支持。

感谢封面制作者张雪的无偿支持。

感谢编程达人王 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

14

第二步:按 F8 执行,并观察如图 2-10-6、2-10-7 所示。

编程达人系列内部教材

有问题,找达人!编程达人!官网: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

分析:这段代码主要是为了让读者明白,带“*”类型的是可以做比较的,必须是同一

类型的,如果不是同一类型的是不可以做比较的。如果读者切换到该程序的反汇编模式下查

看,编译器是当作无符号数进行比较的。

编程达人系列内部教材

有问题,找达人!编程达人!官网:www.bcdaren.com

51

图 9-1-14

总结:

带*的变量,如果类型相同,可以做大小的比较。

我们把这种带“*”号的类型称作指针。

下节介绍 & 符号使用。

练习:

把本小节所有例题全部上机实验一遍,并使用自己的话总结出,各自的规律。