深入研究C语言 第四篇
这里更多探究的是指针的机制。
用debug对下面程序进行分析,记录每一条C语句运行后,相关内存单元的值。
程序a.c
注意理解指针机制
我们编写如下代码:
编译加载进debug查看:
我们先看其反汇编的代码:
在这里我们对比着C语句分析:
第一条语句是将1000H(16进制,以下16进制用H说明,未说明的都为十进制数据。且汇编语言数据都为16进制,不加H说明。)。放置在变量P(偏移地址01FAH)处。
第二句中,使用*的地方,即*p处,这里的语句被翻译成两句,即:MOV BX,[01FA]和ADD AL,[bx]。在这里我们知道,在汇编中,[]代表的是地址,也就是说先将01FAH地址处的数据放到BX中然后在将DS:[BX]中的数据加到AL中。
第三句中,在使用&处的语句,即p=&ch;处,我们看到在上条语句中,AL最后放到了01A8H处,也就是01A8H处是ch的存放位置。我们看到,p=&ch;这条语句被翻译成了:WORD PTR [01FA],01A8。也就是说,将ch在内存中的存放位置这个数,放在了DS:[01FA]处。从这里我们能看出。1.指针类型也是存放在内存中,存放的内容是一个地址。2.指针类型是一个2字节的。
第四句中,是用*P处。我们看到,首先,将p的地址中存放的地址(也就是ch所占的内存),放到BX中,然后将DS:[BX]的数据放到al中,inc al。我们可以看到,*指针所对应的操作是取指针指向的内存处的数据。
第五句,这里看到了双指针,我们来看,分析上下文我们得出,这句赋值的语句被翻译成了MOV BX,[01A6] 我们看到,这里是将指针P的地址放在了pa中。
我们查看单步执行的过程,对比我们的分析:
在这里我们看到,第一二句执行的时候,确实是将1000H处的数据放到了AL中,也就是P指向的位置的数据。
在这里我们看到,对*p的处理,是将指针内的数据给BX,并将DS:[BX]处的数据放在AL中。
我们看到,这里是将指针p的地址给了pa。
这里调用的时候,是先将01A6H处的数据传给BX,再将DS:[BX]处的数据放到BX中,也就是说*的作用是将这里的数据当做地址向外拿数据。
在这里我们看到char far*,在放入地址的时候,将DS也放入的进去,这里也可以说明far型的指针变量的大小为四个字节。
而且,指针变量还可以被转换为int型的变量。转换过后,是将指针指向的地址作为int型变量的值。
*(char *)n这里是将n的值作为地址,取这里的char型的值。
综合来看,指针是一种特殊的类型,指针内存放(这里是指针内,存放)的是一个地址。他有2字节和4字节两种形式。&是取地址符,*是取指针指向位置的数据。
程序b.c
注意Struct指针的用法,指针“+”运算的意义。
我们编写程序如下:
我们在反汇编后看到,首先,pstuàname[1]与((*pstu).name[2])在翻译过后的形式是一样的,都是MOV BYTE PTR [ ], 这样的形式。也就是说他们的功能是一样的。其次,对于Struct指针,记录的是Struct的首地址。最后,当指针做“+”运算的时候,其实加上的不是定值,而是它所指向的类型的长度。对于char型是1,对于int型是2,对于自定义类型,是其自定义的数据的长度之和。
我们查看单步的情况:
那么,这样做的意义在哪儿?指针自加,所加上的是其指向的数据类型的长度,那么我们就可以方便的在程序中使用指针,也可以在循环中使用指针。并且,这样的方式使得程序寻找内存的方式更加多样,更加灵活。
程序c.c
注意理解“[]”运算的意义及数组名与指针的关系。
从整体来说,在这里我们可以看出,p的地址是01d0H,pf的地址是01ceH和01ccH;str的首地址为01caH,而01caH里边存的数据是字符串的首地址0194H;a的首地址为01a8H。
我们可以分析出的一个for循环的位置,是从0206H到022eH。
将01CAH(01CA中结合上下语句可以看出是放的N)处的数据放在BX中,然后将BX+0194H处的数据放到AL中,即是数组中的值。 01caH处放的是pf+n的数据,*(pf+n)就是将[1ca]给了bx,然后将al给了[bx],完成在0:200中写入字符串。
第二个for是024AH到026AH,这里我们可以看出*(str+n)功能与*str+*n是相同的。
第三个for是从026EH到029BH,这里我们看出,其inc WORD PTR[01AC]这条指令被替换成了两条指令:SHL DX,1 shl bx,1和inc word ptr [01CA]。这是因为所取的数据变成了int型。
第四个for,在实现上与第三个for是类似的。
综合来看,数组在底层的实现过程和指针在底层实现的过程是一样的。数组名就相当于指向数组空间首地址的指针。而‘数组[下标]’的方式就相当于‘指针+数据类型长度*下标’的方式。
深入研究C语言 第四篇的更多相关文章
- 深入研究C语言 第三篇
本篇研究TC2.0下其他几个工具.同时看看TC由源代码到exe程序的过程. 1. 用TCC将下面的程序编为.obj文件 我们知道,TCC在默认的编译连接一个C语言的源程序a.c的时候分为以下两步: ( ...
- 深入研究C语言 第一篇(续)
没有读过第一篇的读者,可以点击这里,阅读深入研究C语言的第一篇. 问题一:如何打印变量的地址? 我们用取地址符&,可以取到变量的偏移地址,用DS可以取到变量的段地址. 1.全局变量: 我们看到 ...
- Flask最强攻略 - 跟DragonFire学Flask - 第四篇 Flask 中的模板语言 Jinja2 及 render_template 的深度用法
是时候开始写个前端了,Flask中默认的模板语言是Jinja2 现在我们来一步一步的学习一下 Jinja2 捎带手把 render_template 中留下的疑问解决一下 首先我们要在后端定义几个字符 ...
- flask 第四篇 模板语言jinja2
是时候开始写个前端了,Flask中默认的模板语言是Jinja2 现在我们来一步一步的学习一下 Jinja2 捎带手把 render_template 中留下的疑问解决一下 首先我们要在后端定义几个字符 ...
- R语言学习 第四篇:函数和流程控制
变量用于临时存储数据,而函数用于操作数据,实现代码的重复使用.在R中,函数只是另一种数据类型的变量,可以被分配,操作,甚至把函数作为参数传递给其他函数.分支控制和循环控制,和通用编程语言的风格很相似, ...
- 解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译)
解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译) http://improve.dk/how-are-vardecimals-stored/ 在这篇文章,我将深入研究 ...
- RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe
目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...
- 第四篇 Integration Services:增量加载-Updating Rows
本篇文章是Integration Services系列的第四篇,详细内容请参考原文. 回顾增量加载记住,在SSIS增量加载有三个使用案例:1.New rows-add rows to the dest ...
- [老老实实学WCF] 第四篇 初探通信--ChannelFactory
老老实实学WCF 第四篇 初探通信--ChannelFactory 通过前几篇的学习,我们简单了解了WCF的服务端-客户端模型,可以建立一个简单的WCF通信程序,并且可以把我们的服务寄宿在IIS中了. ...
随机推荐
- 怎么部署java项目(从搭建环境说起)
1.服务器需要安装对应开发版本的jdk 在官网下载jdk对应的jdk版本,解压到某个目录下如: root@guchen-ubuntu16-04lts:/home/guchen/usr/java# ls ...
- HBase学习
记录HBase的学习过程.之后会陆续添加内容. 阅读hbase的博客,理解hbase是什么.推荐博文: 1,HBase原理,基础架构,基础概念 2,HBase超详细介绍 --------------- ...
- sass揭秘之@mixin,%,@function
因为文章内含有很多sass代码,如需自己动手查看编译结果,推荐使用sassmeister这款在线编译工具,方便你阅读学习. 在阅读本文章之前,请先确认你已经阅读了上篇文章sass揭秘之变量,不然会给你 ...
- 《On Lisp》第四章第三节图4.3中的prune函数fix
这个函数作者的原意是删除表中test位真的部分,并且表按原样返回. 作者给出的的测试用例如下: (prune #'evenp '(1 2 (3 (4 5) 6) 7 8 (9))) 返回结果是: (1 ...
- 因为此版本的应用程序不支持其项目类型(.csproj)”之解
有的时候vs无缘无故的出现如下错误:"因为此版本的应用程序不支持其项目类型(.csproj),若要打开它,请使用支持此类型项目的版本" 解决办法:如果是这个提示,可能是由于你安装m ...
- 为什么C#中应该用Try-Catch?
[为什么C#中应该用Try-Catch?] http://blog.csdn.net/dier4836/article/details/7292897
- WPF简单导航框架(Window与Page互相调用)
相当多的WPF程序都有着丰富的页面和功能,如何使程序在不同页面间转换并降低资源占用,选择适合自己的导航框架就很重要了.最近花了一点时间做了一个简单的导航框架,并在这个过程中对Window.Page.U ...
- js正则获取图片的src属性及正则分割一个字符串
try{ var str='<P>xczxzxzxcxcxc<IMG src="http://file.ynet.com/2/1612/12/12119048.jp ...
- maven学习(5)-maven中常见错误
maven报错非法字符:\65279 错误 开发中一个项目很早就报这个错,maven报错非法字符:\ 错误, 开发过程中偶尔会遇到,今天终于下决心要解决这个问题 编译java 文件的时候,有些java ...
- CS0012: 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义
entity framework,没在view引用 实体对象时,一直没问题,引用后爆出这个错误来 CS0012: 类型"System.Data.Objects.DataClasses.En ...