理解指针
如题:理解指针 转载请保留作者和地址 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:\abc\bcd\cde \n"; char temp2[100] = "c:/abc/bcd/cde \n"; char temp3[100] = "c:\\abc\\bcd\\cde \n"; */ //&取地址 运算符:取出内存地址 //*间接寻址 运算符:得到内存地址里面的值 int ival = 100; //地址为0x00adf75c{100} int *p = &ival; //取ival的地址 赋给p的指针(地址0x00adf75c 赋给*p) ival = 200; //改ival的值0x00adf75c{200} //printf("\n ival = %d, &ival = 0x%x, *p =0x%x ", ival, &ival, *p); //little endian int **b = &p;//b是二级指针, 第一个指针地址是0x00adf75c{200}(0x00adf75c存的值为200), 第二个指针地址是0x00adf750 //printf("\n 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("\n c >>>>>>>>>>>> **c =0x%d, *c=0x%d, c =%d", **c, *c, c); int d = **b;//二级指针b , 间接寻址 再间接寻址(也就是ival指针地址的值),赋给d return 0; }
再看看汇编是如何实现的
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:\abc\bcd\cde \n"; char temp2[100] = "c:/abc/bcd/cde \n"; char temp3[100] = "c:\\abc\\bcd\\cde \n"; */ //&取地址 运算符:取出内存地址 //*间接寻址 运算符:得到内存地址里面的值 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("\n 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("\n 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("\n 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 }
图:
//==========分割线
有个问题提下:
为什么【一级指针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\n", cpp[2][1] + 2); printf("%s\n", **++cpp);//注意!!!!这里cpp首地址 向下偏移+1 printf("%s\n", *--*++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\n", cpp[1][3] + 3); return 0; }