有趣的指针

简介: 有趣的指针

废话不多说,请看以下代码:

#define buffer ((char *) *( (int far *)0x200 ))
main(){

     buffer=(char *)malloc(20);
     buffer[10]=0;
     while(buffer[10]!=8){
          buffer[buffer[10]]='a' + buffer[10];
          buffer[10]++;
     }
     free(buffer);
}

 

我们不妨忽略#define buffer ...这个语句,把buffer看做b代码如下:

main(){

     b=(char *)malloc(20);
     b[10]=0;
     while(b[10]!=8){
          b[b[10]]='a' + b[10];
          b[10]++;
     }
     free(b);
}

b指向了刚刚开辟的20个字节大小的内存首地址,且b移动的单元为1个字节(即char类型单元大小)

b[10]=0意思是由b指向的首地址向后移动10*1(b的移动单元)个单位到达的地址,也就是第11个元素所在内存的首地址

根据n[10]=0;b[10]!=8和循环中的b[10]++;可知该循环循环8次

b[b[10]]='a'+b[10];这句什么意思?
循环第一次:b[0]='a'+0
循环第二次:b[1]='a'+1
循环第八次:b[7]='a'+7
我们枚举下,可知原来是把a~h八个字符分别装到b[0]~b[7]中

free(b);释放b所指向的地址,可能问题来了?free如何知道b所指向的空间有20B大小呢?

答:存放在b所指空间大小存放在寄存器ax中,并压入栈ss中保存。

(寄存器:cpu中可以储存数据的器件)

举个栗子附图:

我们写的c代码如下:

我们使用系统自带的debug调试一次这个程序


首先,已知main在我的虚拟机中的偏移地址为01fa,这样我们直接跳至cs:1fa处,

找到main函数中转化成汇编代码的c语言代码。

SUB SP,+02 (汇编指令)等价于 sp+=2; 想必大家已经猜出来了,这正是char *b;其含义就是初始化一个空间给b(姑且可以这样抽象的理解),而这个空间将放在栈(ss:sp注:括号中不理解没关系,ss<<2+sp代表的是栈的物理首地址)中,sp是指向栈顶的,所以其+2(为什么+2?因为b是一个指针,指针大小是2Byte,栈存储单位是1B,所以指针入栈栈顶需要+2,姑且可以这样抽象的理解)

之后,MOV AX,0014 (汇编指令)作用等价于AX=20;这里的0014是16进制,转化为10进制就是20,即我们malloc的空间大小。

PUSH AX (汇编指令)翻译过来就是ax的值入栈,把ax的值保存在栈中,就是保存malloc分配空间size的值。

于是乎,我们证明了free是如何知道malloc所分配的空间大小。ax=20;ax入栈;到运行free时在从栈中取出20即可。

简而言之,这个简化的程序就是把a~f8个字符写入申请的b[0]~b[7]中

 

那么,重点来了(注意!这里才是重点)

define buffer ((char *) *( (int far *)0x200 ))

这里第一反应就是:Are you kidding me?

你会说为啥变量变成一个数了呢?还是16进制的数。

答:首先,*( (int far *)0x200 )

far:指明后面的对象是一个确切的物理地址(就是根据0x200能直接在内存中找到是0x200的物理地址)

第一个* :代表后面的对象是一个内存空间

第二个* :代表后面的对象是一个内存空间地址

(int far *)0x200:表示这个一个物理地址,该地址的存储单位是2Byte(int即2Byte,但有些操作系统不同,这里不多做解释)

*(int far *)0x200:表示0x200这个物理地址的内存空间

(char *) *( (int far *)0x200 ):char * 纯属修饰的是内存空间中的数据,表示这个数据是一个char 型指针,(以下可以跳过)

本质是:这个数据是一个地址,一个单位为1Byte的空间的地址。也就是0x200地址空间中装着一个单位为1Byte的地址,这个地址我们还未确定,因为我们还未初始化。

 

b=(char *)malloc(20);初始化0x200地址内存,即把malloc开辟的首地址装入0x200中

b即装在0x200地址内存中的数据。

b[10]:装在0x200地址内存中的数据是一个地址,b[10]即这个地址+10Byte(char)地址内存中的数据。

这里来波实战:

首先,我们写一个c代码,这里的编译器用的是古老的TC,为什么要用这么老的东西?

因为越古老的东西越不存在那些华丽而又繁杂的装饰,资源分配,链接,预编译特别简单,便于我们分析,我们甚至可以自己动手写一个c语言编译器开发环境。

之后,我们运行完这个程序,查看0x200地址的内存,(图中0000:0200代表0x200地址)

发现内存数据为00 00 ,根据我们前面的推测,内存数据00 00 是一个地址,是malloc分配空间的首地址。

为什么只取前两个?

malloc此类的函数分配的空间都是在栈中,所以,对应的前两个字节应该是栈的偏移地址。

 

于是,我们来到地址00 00 处:

ds:0000可以抽象理解为查看0000地址处的内存。

这里前面是以16进制表示,后面表示的是16进制转化为ascll的值

我们可以看到a~h的ascll码十六进制和其转化为字符形式,从b~(b+7)地址内存中依次存储(这里b的地址即00 00)

于是,我们证明了0x200中存的数据是一个地址,且这个地址是malloc的首地址。

最后留一个小彩蛋,那么b[10]在哪呢?其中的值又是多少?仔细看看00 00地址内存的那张图,你将会得到答案!

 

 

目录
相关文章
|
存储 人工智能 编译器
c中的指针详解
c中的指针详解
|
7月前
|
存储 算法 C++
C++指针
C++指针
47 0
|
7月前
|
C++ 编译器
|
7月前
|
存储
什么是指针?
什么是指针。
49 1
|
7月前
|
存储
浅谈指针(1)
浅谈指针(1)
|
存储 安全 C语言
C语言知识点之 指针1
C语言知识点之 指针1
64 0
|
Perl
C指针(详解)
C指针(详解)
179 0
|
存储 编译器 C++
认识C++指针
认识C++指针
指针(一)
系统给内存的每一个字节,分配一个编号,这个编号就是内存地址
指针(一)
|
存储 人工智能 C语言