指针和引用

 

The most important difference between  pointers in C and those in C++ is that C++ is a more strongly typed language.This stands out where void * is concerne.

代码:

bird * b;

rock * r;

void * v;

v=r;

b=v;//这两个赋值在C编译器通过,在C++编译器不通过

void * 在C中表示指向任意的类型. 在C++中表示指向void类型.

 

A reference (&) is like a const pointer that is automatically dereferenced.There are certain rules when using references.

1.A reference must be initialized when it is created.(Pointers can be intialized at any time).

2.Once a reference is initialized to an object,it can not be changed to refer to another object.

(Pointers can  be pointed to another object at any time).

3.you can not have NULL reference.

把引用认为是一个对象的别名,上面规则就好理解了.

下面看一段代码的汇编来理解

#include <iostream>
using namespace std;

int* f1(int * px)
{
  (*px)++;
  return px;

}

int& g1(int & rx)
{
 rx++;
 return rx;
}

int main()
{
 int a=1;
   f1(&a);
   g1(a);
   return 0;
}

 

  1. 6:
  2. 17:   int main()
  3. 18:   {
  4. 004012E0   push        ebp
  5. 004012E1   mov         ebp,esp
  6. 004012E3   sub         esp,44h
  7. 004012E6   push        ebx
  8. 004012E7   push        esi
  9. 004012E8   push        edi
  10. 004012E9   lea         edi,[ebp-44h]
  11. 004012EC   mov         ecx,11h
  12. 004012F1   mov         eax,0CCCCCCCCh
  13. 004012F6   rep stos    dword ptr [edi]
  14. 19:       int a=1;
  15. 004012F8   mov         dword ptr [ebp-4],1//SS:[ebp-4]存放的是a变量的值
  16. 20:      f1(&a);
  17. 004012FF   lea         eax,[ebp-4]//eax存的是a变量的地址
  18. 00401302   push        eax//函数的参数入栈
  19. 00401303   call        @ILT+10(f1) (0040100f)//跟进去
  20. /*
  21. 00401308   add         esp,4
  22. 21:      g1(a);
  23. 0040130B   lea         ecx,[ebp-4]
  24. 0040130E   push        ecx
  25. 0040130F   call        @ILT+20(g1) (00401019)
  26. 00401314   add         esp,4
  27. 22:      return 0;
  28. 00401317   xor         eax,eax
  29. 23:   }
  30. 00401319   pop         edi
  31. 0040131A   pop         esi
  32. 0040131B   pop         ebx
  33. 0040131C   add         esp,44h
  34. 0040131F   cmp         ebp,esp
  35. 00401321   call        __chkesp (004081f0)
  36. 00401326   mov         esp,ebp
  37. 00401328   pop         ebp
  38. 00401329   ret
  39. */
  40. @ILT+10(?f1@@YAPAHPAH@Z):
  41. 0040100F   jmp         f1 (00401260)
  42. 4:    int* f1(int * px)
  43. 5:    {
  44. 00401260   push        ebp
  45. 00401261   mov         ebp,esp
  46. 00401263   sub         esp,40h
  47. 00401266   push        ebx
  48. 00401267   push        esi
  49. 00401268   push        edi
  50. 00401269   lea         edi,[ebp-40h]
  51. 0040126C   mov         ecx,10h
  52. 00401271   mov         eax,0CCCCCCCCh
  53. 00401276   rep stos    dword ptr [edi]
  54. 6:      (*px)++;
  55. 00401278   mov         eax,dword ptr [ebp+8]
  56. //注意这句 ebp+8指的内存里存的是先前eax的值,即a的地址.
  57. //所以操作后 eax是a的地址.
  58. 0040127B   mov         ecx,dword ptr [eax]//ecx=*px
  59. 0040127D   add         ecx,1
  60. 00401280   mov         edx,dword ptr [ebp+8]//edx=&px注意
  61. 00401283   mov         dword ptr [edx],ecx//这句改变了a的值,
  62. 7:      return px;
  63. 00401285   mov         eax,dword ptr [ebp+8]
  64. 8:
  65. 9:    }
  66. 00401288   pop         edi
  67. 00401289   pop         esi
  68. 0040128A   pop         ebx
  69. 0040128B   mov         esp,ebp
  70. 0040128D   pop         ebp
  71. 0040128E   ret
  72. 返回到main函数
  73. 00401308   add         esp,4 //移除函数参数
  74. 21:      g1(a);
  75. 0040130B   lea         ecx,[ebp-4]//注意和前面的指针调用一模一样
  76. 0040130E   push        ecx//函数参数入栈
  77. 0040130F   call        @ILT+20(g1) (00401019)跟进去
  78. @ILT+20(?g1@@YAAAHAAH@Z):
  79. 00401019   jmp         g1 (004012a0)
  80.  int& g1(int & rx)
  81. 12:   {
  82. 004012A0   push        ebp
  83. 004012A1   mov         ebp,esp
  84. 004012A3   sub         esp,40h
  85. 004012A6   push        ebx
  86. 004012A7   push        esi
  87. 004012A8   push        edi
  88. 004012A9   lea         edi,[ebp-40h]
  89. 004012AC   mov         ecx,10h
  90. 004012B1   mov         eax,0CCCCCCCCh
  91. 004012B6   rep stos    dword ptr [edi]
  92. 13:       rx++;
  93. //我们来和指针做个比较,代码一模一样
  94. /*
  95. 6:      (*px)++;
  96. 00401278   mov         eax,dword ptr [ebp+8]
  97. //注意这句 ebp+8指的内存里存的是先前eax的值,即a的地址.
  98. //所以操作后 eax是a的地址.
  99. 0040127B   mov         ecx,dword ptr [eax]//ecx=*px
  100. 0040127D   add         ecx,1
  101. 00401280   mov         edx,dword ptr [ebp+8]//edx=&px注意
  102. 00401283   mov         dword ptr [edx],ecx//这句改变了a的值,
  103. 7:      return px;
  104. 00401285   mov         eax,dword ptr [ebp+8]
  105. */
  106. 004012B8   mov         eax,dword ptr [ebp+8]
  107. 004012BB   mov         ecx,dword ptr [eax]
  108. 004012BD   add         ecx,1
  109. 004012C0   mov         edx,dword ptr [ebp+8]
  110. 004012C3   mov         dword ptr [edx],ecx
  111. 14:       return rx;
  112. 004012C5   mov         eax,dword ptr [ebp+8]
  113. 15:   }
  114. 004012C8   pop         edi
  115. 004012C9   pop         esi
  116. 004012CA   pop         ebx
  117. 004012CB   mov         esp,ebp
  118. 004012CD   pop         ebp
  119. 004012CE   ret
  120. 返回到main函数
  121. 00401314   add         esp,4//移除函数参数
  122. 22:      return 0;
  123. 00401317   xor         eax,eax
  124. 23:   }
  125. 00401319   pop         edi
  126. 0040131A   pop         esi
  127. 0040131B   pop         ebx
  128. 0040131C   add         esp,44h
  129. 0040131F   cmp         ebp,esp
  130. 00401321   call        __chkesp (004081f0)也跟进去看看
  131. 00401326   mov         esp,ebp
  132. 00401328   pop         ebp
  133. 00401329   ret
  134. _chkesp:
  135. 004081F0   jne         __chkesp+3 (004081f3)//不相等就转去处理异常了
  136. 004081F2   ret
  137. 004081F3   push        ebp
  138. 004081F4   mov         ebp,esp
  139. 004081F6   sub         esp,0
  140. 004081F9   push        eax
  141. 004081FA   push        edx
  142. 004081FB   push        ebx
  143. 004081FC   push        esi
  144. 004081FD   push        edi
  145. 004081FE   push        offset string "The value of ESP was not properl"... (004312b4)
  146. 00408203   push        offset string "" (004311b4)
  147. 00408208   push        2Ah
  148. 0040820A   push        offset string "i386//chkesp.c" (004312a4)
  149. 0040820F   push        1
  150. 00408211   call        _CrtDbgReport (0040ca70)
  151. 00408216   add         esp,14h
  152. 00408219   cmp         eax,1
  153. 0040821C   jne         __chkesp+2Fh (0040821f)
  154. 0040821E   int         3
  155. 0040821F   pop         edi
  156. 00408220   pop         esi
  157. 00408221   pop         ebx
  158. 00408222   pop         edx
  159. 00408223   pop         eax
  160. 00408224   mov         esp,ebp
  161. 00408226   pop         ebp
  162. 00408227   ret

总结:从此例汇编层来看,引用和指针是没有区别的.

 

那我就有一个地方想不明白了

#include <iostream>

using namespace std;

int main()

{

  int a=3;

  int *pa=&a;

  int &  ra=a;

 cout<<&pa<<endl;

cout<<&ra<<endl;

cout<<&a<<endl;

return 0;

}

结果:

0012FF78

0012FF7C

0012FF7C

这两个输出为什么不同?

继续跟踪汇编


1:    #include <iostream>
2:
3:    using namespace std;
4:
5:    int main()
6:
7:    {
00401250   push        ebp
00401251   mov         ebp,esp
00401253   sub         esp,54h//(54h-40h)/04h=20/4=5
00401256   push        ebx
00401257   push        esi
00401258   push        edi
00401259   lea         edi,[ebp-54h]
0040125C   mov         ecx,15h
00401261   mov         eax,0CCCCCCCCh
00401266   rep stos    dword ptr [edi]
8:
9:      int a=3;
00401268   mov         dword ptr [ebp-4],3//第一个局部变量a
10:
11:     int *pa=&a;
0040126F   lea         eax,[ebp-4]
00401272   mov         dword ptr [ebp-8],eax //第二个局部变量pa
12:
13:     int &  ra=a;
00401275   lea         ecx,[ebp-4]
00401278   mov         dword ptr [ebp-0Ch],ecx // 第三个局部变量ra


14:     int * pb=&a;
0040127B   lea         edx,[ebp-4]
0040127E   mov         dword ptr [ebp-10h],edx//第四个局部变量pb
15:           pb=&ra;
00401281   mov         eax,dword ptr [ebp-0Ch]
00401284   mov         dword ptr [ebp-10h],eax


16:     int ** pc=&pa;
00401287   lea         ecx,[ebp-8]//第五个局部变量
0040128A   mov         dword ptr [ebp-14h],ecx
17:
18:
19:   return 0;
0040128D   xor         eax,eax
20:
21:   }
0040128F   pop         edi
00401290   pop         esi
00401291   pop         ebx
00401292   mov         esp,ebp
00401294   pop         ebp
00401295   ret
总结:

搞明白了,引用其实就是一个指针,只是编译器会自动对它解析,并进行代码优化.

也就是 A reference (&) is like a const pointer that is automatically dereferenced.

所以上面的代码

 

cout<<&ra<<endl;编译器对它做了转化  cout<< &(*ra)<<endl;

你可能感兴趣的:(指针和引用)