理解指针

如题:理解指针  转载请保留作者和地址 http://www.cnblogs.com/scotth/p/3703616.html

VS如何看汇编代码(DEBUG状态)

  Debug->Windows->DisAssambly即可看到汇编窗口

先看看C++代码

    BYTE data[1024] = { 1,2,3 };
    BYTE* pdata(data);
    BYTE** ppdata(&pdata);
    *ppdata[0] = '5';

int _tmain(int argc, _TCHAR* argv[])
{
    /*
    char temp[100] = "c:abccdcde 
";
    char temp2[100] = "c:/abc/bcd/cde 
";
    char temp3[100] = "c:\abc\bcd\cde 
";
    */

    //&取地址   运算符:取出内存地址
    //*间接寻址 运算符:得到内存地址里面的值

    int ival = 100; //地址为0x00adf75c{100}
    int *p = &ival;    //取ival的地址  赋给p的指针(地址0x00adf75c 赋给*p)
    ival = 200;        //改ival的值0x00adf75c{200}


    //printf("
 ival = %d, &ival = 0x%x, *p =0x%x ", ival, &ival, *p);

    //little endian
    int **b = &p;//b是二级指针,     第一个指针地址是0x00adf75c{200}(0x00adf75c存的值为200),   第二个指针地址是0x00adf750
    //printf("
 b>>>>>>>>> **b =0x%d, *b=0x%x,  b =%x", **b, *b, b);


    //============================================================================
    //通过debug可以看到二级指针的信息    0x00adf750{0x00adf75c{200}}


    int *first = &(**b);
    //1.按照()优先级, 二级指针b  先间接寻址,再间接寻址 得到200的值, 然后取地址  得到ival的地址(也就是*p的值  0x00adf75c{200})
    
    //汇编过程
    //1.  【二级指针b】把0x00adf750 赋给eax
    //2.  eax(间接寻址后)得到 0x00adf75c{200} 赋给ebx,   再取地址  赋给 *first(first指针地址 为0x00adf75c{200})
    
    
    int *second = *b;    
    //二级指针b先把0x00adf750{0x00adf75c{200}}   赋给 寄存器eax, 
    //eax 0x00adf750(间接寻址后)得到0x00adf75c{200}  赋给 *second(second指针地址 为0x00adf75c{200})

    int **c = b;//二级指针 b 赋给二级指针c
    //printf("
 c >>>>>>>>>>>> **c =0x%d, *c=0x%d,  c =%d", **c, *c, c);


    int d = **b;//二级指针b , 间接寻址 再间接寻址(也就是ival指针地址的值),赋给d

    return 0;
}
View Code

再看看汇编是如何实现的

int _tmain(int argc, _TCHAR* argv[])
{
00E213B0  push        ebp  
00E213B1  mov         ebp,esp  
00E213B3  sub         esp,118h  
00E213B9  push        ebx  
00E213BA  push        esi  
00E213BB  push        edi  
00E213BC  lea         edi,[ebp-118h]  
00E213C2  mov         ecx,46h  
00E213C7  mov         eax,0CCCCCCCCh  
00E213CC  rep stos    dword ptr es:[edi]  
00E213CE  mov         eax,dword ptr ds:[00E28000h]  
00E213D3  xor         eax,ebp  
00E213D5  mov         dword ptr [ebp-4],eax  
    /*
    char temp[100] = "c:abccdcde 
";
    char temp2[100] = "c:/abc/bcd/cde 
";
    char temp3[100] = "c:\abc\bcd\cde 
";
    */

    //&取地址   运算符:取出内存地址
    //*间接寻址 运算符:得到内存地址里面的值

    int ival = 100; //地址为0x00adf75c{100}
00E213D8  mov         dword ptr [ival],64h  
    int *p = &ival;    //取ival的地址  赋给p的指针(地址0x00adf75c 赋给*p)
00E213DF  lea         eax,[ival]  
00E213E2  mov         dword ptr [p],eax  
    ival = 200;        //改ival的值0x00adf75c{200}
00E213E5  mov         dword ptr [ival],0C8h  


    //printf("
 ival = %d, &ival = 0x%x, *p =0x%x ", ival, &ival, *p);

    //little endian
    int **b = &p;//b是二级指针,     第一个指针地址是0x00adf75c{200}(0x00adf75c存的值为200),   第二个指针地址是0x00adf750
00E213EC  lea         eax,[p]  
00E213EF  mov         dword ptr [b],eax  
    //printf("
 b>>>>>>>>> **b =0x%d, *b=0x%x,  b =%x", **b, *b, b);


    //============================================================================
    //通过debug可以看到二级指针的信息    0x00adf750{0x00adf75c{200}}


    int *first = &(**b);
00E213F2  mov         eax,dword ptr [b]  
00E213F5  mov         ecx,dword ptr [eax]  
00E213F7  mov         dword ptr [first],ecx  
    //1.按照()优先级, 二级指针b  先间接寻址,再间接寻址 得到200的值, 然后取地址  得到ival的地址(也就是*p的值  0x00adf75c{200})
    
    //汇编过程
    //1.  【二级指针b】把0x00adf750 赋给eax
    //2.  eax(间接寻址后)得到 0x00adf75c{200} 赋给ebx,   再取地址  赋给 *first(first指针地址 为0x00adf75c{200})
    
    
    int *second = *b;    
00E213FA  mov         eax,dword ptr [b]  
00E213FD  mov         ecx,dword ptr [eax]  
00E213FF  mov         dword ptr [second],ecx  
    //二级指针b先把0x00adf750{0x00adf75c{200}}   赋给 寄存器eax, 
    //eax 0x00adf750(间接寻址后)得到0x00adf75c{200}  赋给 *second(second指针地址 为0x00adf75c{200})

    int **c = b;//二级指针 b 赋给二级指针c
00E21402  mov         eax,dword ptr [b]  
00E21405  mov         dword ptr [c],eax  
    //printf("
 c >>>>>>>>>>>> **c =0x%d, *c=0x%d,  c =%d", **c, *c, c);


    int d = **b;//二级指针b , 间接寻址 再间接寻址(也就是ival指针地址的值),赋给d
00E21408  mov         eax,dword ptr [b]  
00E2140B  mov         ecx,dword ptr [eax]  
00E2140D  mov         edx,dword ptr [ecx]  
00E2140F  mov         dword ptr [d],edx  

    return 0;
00E21412  xor         eax,eax  
}
View Code

图:

//==========分割线

有个问题提下:

为什么【一级指针0x00adf75c】定义早于【二级指针0x00adf750 】但是二级指针的内存地址在低位

原因:

机器是intel x64  【little endian机】

所以每8位,高位地址在前,低位地址在后面,所以先分配0x00adf75c,再分配0x00adf750

参考 [内存布局](http://www.cnblogs.com/scotth/p/4330649.html)

大端小端知识传送门(深入理解计算机里面也有讲)

http://en.wikipedia.org/wiki/Endianness

 //===========================分割线

有一个指针题,题目如下:

看输出什么答案+代码。都没什么意义,但是对于理解内存还是可以的。

int _tmain(int argc, _TCHAR* argv[])
{
    char* c[] = { "ENTER", "NEW", "POINT", "FIRST" };
    char** cp[] = { c + 3, c + 2, c + 1, c };
    char*** cpp = cp;
    
    printf("%s
", cpp[2][1] + 2);
    printf("%s
", **++cpp);//注意!!!!这里cpp首地址 向下偏移+1
    printf("%s
", *--*++cpp + 3);//
    //先++cpp (地址再偏移+1)
    //间接寻址*,再间接寻址*--,这里相当于cpp[2][0]的--,     cpp[2][0]=new  cpp[2][1]=point  cpp[2][2]=null  cpp[2][3]=null
    //cpp[2][0]=new,基础上-- ,已经没有内容了!!    但是c的内存是连续的,所以还会--, 为enter
    //enter 字符再+3  结果为 er

    //偏移后的结果
    printf("%s
", cpp[1][3] + 3);
    
    return 0;
}
View Code

原文地址:https://www.cnblogs.com/scotth/p/3703616.html