C++中的指针与引用详细解读.docx

上传人:牧羊曲112 文档编号:4883275 上传时间:2023-05-21 格式:DOCX 页数:13 大小:174.58KB
返回 下载 相关 举报
C++中的指针与引用详细解读.docx_第1页
第1页 / 共13页
C++中的指针与引用详细解读.docx_第2页
第2页 / 共13页
C++中的指针与引用详细解读.docx_第3页
第3页 / 共13页
C++中的指针与引用详细解读.docx_第4页
第4页 / 共13页
C++中的指针与引用详细解读.docx_第5页
第5页 / 共13页
亲,该文档总共13页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《C++中的指针与引用详细解读.docx》由会员分享,可在线阅读,更多相关《C++中的指针与引用详细解读.docx(13页珍藏版)》请在三一办公上搜索。

1、C+中的指针与弓I用详细解读1、指针和引用的定义在深入介绍之前我们首先来看一下指针和引用的定义、指针和引用的区别,然后分别针 对指针和引用展开讨论,深入细节为何有这些差异。指针的权威定义:In a declaration T D where D has the form * cv-qualifier-seqopt D1 And the type of the identifier in the declaration T D1 is “ derived-declarator-type-list T”,then the type of the identifier of D is “ deriv

2、ed-declarator-type-list cv-qualifier-seq pointer to T” . The cv-qualifiers apply to the pointer and not to the object pointer to.摘自ANSI C+ Standard注:可能有些读者并不明白cv-qualifier-seqCV-qualifiers(CV 限定符)CV-qualifiers 有三种:const-qualifier(const 限定符)、Volatile-qualifier(volatile 限定符)、以及 const-volatile-qualifie

3、r(const-volatile 限定符)。const类对象的非静态、非mutable、以及非引用数据成员是const-qualified;volatile类对象的非静态、非引用数据成员是volatile-qualified;const-volatile类对象的非静态、非引用数据成员是const-volatile-qualified。当CV-qualifiers用于限定数组类型时,实际上是数组成员被该CV-qualifiers限定,而非该数 组类型。复合类型并不因其成员被CV-qualifier限定而被该CV-qualifier限定,也就是说,即使复合类 型的成员有CV-qualifier限定

4、,该复合类型也不是CV-qualified对象。引用的权威定义:In a declaration T D where D has the form& D1 And the type of the identifier in the declaration T D1 is “ derived-declarator-type-list T ” , then the type of the identifier of D is “ derived-declarator-type-list cv-qualifier-seq reference to T ” . Cv-qualified referen

5、ces are ill-formed except when the cv-qualifiers are introduced through the use of a typedef or a template type argument, in which case the cv-qualifiers are ignored.摘自ANSI C+ Standard上面这些定义初看有些难懂,如果是这样的话,那说明你对C+还不够熟悉,你还有很长的 路要走。下面用通俗易懂的话来概述一下: 指针-对于一个类型T,T*就是指向T的指针类型,也即一个T*类型的变量能够保存一个T 对象的地址,而类型T是可

6、以加一些限定词的,如const、volatile等等。见下图,所示指针 的含义:ichar c=J3J;1-、.E i * IP I 二 2 ID 3 q a #,3 5 mtHLCpp X(Global Rope)m mainfint argcP ehjr *b arv)-i-nclude uffing naBes-paee sld;-mt n-amCirit arjc, chatr* arg.)E rror listLPt 1-10; inlil ref P XT retutn 0:teit.cpp腿3时5CoJumfl方可娉二Q 2 Errars 0 Warnings.: 0 Messa

7、ges mr 口 5掂 ref ; it;编St耕瞄网R Error List Output2 IntelliSniK refereiwr vjirFable *ref* requires an init诂如tr而声明指针是可以不指向任何对象,也正是因为这个原因,使用指针之前必须做判空操作, 而引用就不必。其次,引用不可以改变指向,对一个对象”至死不渝”;但是指针可以改变指向,而指向其 它对象。说明:虽然引用不可以改变指向,但是可以改变初始化对象的内容。例如就+操 作而言,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使 指针指向下一个对象,而不是改变所指对象的内容。见

8、下面的代码:#include using namespace std;int main(int argc,char* argv)int i=10;int& ref=i;ref+;cout i= iendl;coutvv ref= vvrefv vendl;int j=20;ref=j;ref+;coutv v i= vviv vendl;coutvv ref= vvrefv vendl;coutv v j= vvj v vendl;return 0;对ref的+操作是直接反应到所指变量之上,对引用变量ref重新赋值” ref=j”,并不会改 变ref的指向,它仍然指向的是i,而不是j。理所当然

9、,这时对ref进行+操作不会影响到 jo而这些换做是指针的话,情况大不相同,请自行实验。输出结果如下:曲 C:wi ndows5ystem32cmd,exep.=ll Lef=llL=21Lef=21h=20青按任意键继续再次,引用的大小是所指向的变量的大小,因为引用只是一个别名而巳;指针是指针本身的 大小,4个字节。见下图所示:- w e航that * argvj(Globd ScopeUincludt flincludt usirij nanejrace std:-int aainiiwt arjcT char*- argv)s+zing sr= ;siting raf-ttr;wtrin

10、g* p&irrter=Sstr;Cautref r tpomt er : *pcmtter卓ntjl:cout siseaff (ref): eiesof (ref) sizf of (pami er): main(int a rgc, char * argv)Line Column ProjectIntellFSenses expression mtist be a modifiable lvalue9 2 Errors出 0 Warnings 0 Messagesj 2 IntelliSenr: exprea-siori must be a tetcpp el A JlnX hrlste

11、stcppDeE-criprionError UstQ 2 EffortDescription! 0 Ws rning Q r?l5?ages1 error C3S92: ref 不螳始簿量JKtfi心txpp91 error C3892: painter i 苏髭妈SI皇屈 testcpp(Gbbal Scope) * mainfimt iirg-c, char * argv)- intarac char* arjv)mt* const pointer mtt refreturn 0:rror ListQt 4 Errors 0 Warnings 1) 0 Mes$ag;e&Descript

12、ion,1 error CJJ734: pointer- :testx:ppI I 际则 2 error 53O:云f:逐初娜君甬 j 3 IntelliSenseE const variable *pomter, requi res an iniitializerj4 IntelliStinser reference vrioble 11 ref* r?口(“gg i*n多:口1te&Lcpptestcppte-stcppte&ttestteitCdiurm Project常量指针常量VS常量引用常量 常量指针常量:指向常量的指针常量,可以定义一个指向常量的指针常量,它必须在定义时 初始化。

13、常量指针常量定义” const int* const pointer=&c”告诉编译器,pointer和*pointer都 是常量,他们都不能作为左值进行操作。而就不存在所谓的”常量引用常量”,因为跟上面讲的一样引用变量就是引用常量。C+不 区分变量的const引用和const变量的引用。程序决不能给引用本身重新赋值,使他指向另 一个变量,因此引用总是const的。如果对引用应用关键字const,起作用就是使其目标称为 const 变量。即没有:Const double const& a=1;只有 const double& a=1;总结:有一个规则可以很好的区分const是修饰指针,还是修饰

14、指针指向的数据一一画一条 垂直穿过指针声明的星号(*),如果const出现在线的左边,指针指向的数据为常量;如 果const出现在右边,指针本身为常量。而引用本身与天俱来就是常量,即不可以改变指向。4、指针和引用的实现我们利用下面一段简单的代码来深入分析指针和引用:#include using namespace std;int main(int argc, char* argv) int i=1;int& ref=i;int x=ref;coutx is xendl;ref=2;int* p=&i;coutref = ref, i = iendl;上面的代码用g+ test.c编译之后,然后

15、反汇编objdump -d a.out,得到main函数的一段汇编代码如下:08048714 : 8048714: 55push %ebp8048715: 89 e5 mov %esp,%ebp8048717:83 e4 f0and $0xfffffff0,%esp/为 main 函数的参数 argc、argv 保留位置804871a: 56push %esi804871b: 53push %ebx804871c: 83 ec 28sub $0x28,%esp804871f: c7 44 24 1c 01 00 00 movl $0x1,0x1c(%esp) /将 0x1 存到 esp 寄存器

16、中,即 int i=18048726: 008048727: 8d 44 24 1c lea 0x1c(%esp),%eax/ esp 寄存器里的变量 i 的地址传给 eax804872b: 89 44 24 18mov %eax,0x18(%esp)/将寄存器eax中的内容(i的地址)传给寄8048733: 8b 00存器中的变量ref,即int& ref=i804872f: 8b 44 24 18地址mov 0x18(%esp),%eax/将寄存器 esp 中的 ref 传给 eax,即 i 的mov (%eax),%eax/以寄存器eax中的值作为地址,取出值给eax8048735: 8

17、9 44 24 14 的 x,即 x=ref8048739: c7 44 24 04 00 89 04movl $0x8048900,0x4(%esp)mov %eax,0x14(%esp) /将寄存器eax中的值传给寄存器esp中8048740: 088048741: c7 04 24 40 a0 04 08 movl $0x804a040,(%esp)8048748:e8 cb fe ff ffcall 8048618804874d: 8b 54 24 148048751: 89 54 24 04mov %edx,0x4(%esp)8048755: 89 04 24mov %eax,(%e

18、sp)8048758: e8 5b fe ff ffcall 80485b8 mov 0x14(%esp),%edx804875d: c7 44 24 04 38 86 04 movl $0x8048638,0x4(%esp) 8048764: 088048765: 89 04 24mov %eax,(%esp)8048768: e8 bb fe ff ff call 8048628 /从 80487398048768 这 些行就是执行coutx is vvxvvendl;804876d: 8b 44 24 18mov 0x18(%esp),%eax/将寄存器 esp 中的 ref 传到 ea

19、x 中8048771: c7 00 02 00 00 00movl $0x2,(%eax) /将 0x2 存到 eax 寄存器中8048777: 8d 44 24 1clea 0x1c(%esp),%eax/ esp寄存器里的变量i的地址传给eax804877b: 89 44 24 10mov %eax,0x10(%esp) /将寄存器eax中的内容(即i的地址)传到寄存器esp中的p804877f: 8b 5c 24 1cmov 0x1c(%esp),%ebx8048783: 8b 44 24 18mov 0x18(%esp),%eax8048787: 8b 30mov (%eax),%es

20、i8048789: c7 44 24 04 06 89 04movl $0x8048906,0x4(%esp)8048790: 088048791: c7 04 24 40 a0 04 08movl $0x804a040,(%esp)8048798:e87bfeffffcall8048618804879d: 89 74 24 04mov %esi,0x4(%esp)80487a1: 89 04 24mov %eax,(%esp)80487a4: e8 0f fe ff ffcall 80485b8 80487a9: c7 44 24 04 0d 89 04 movl $0x804890d,0x

21、4(%esp)80487b0: 0880487b1: 89 04 24mov %eax,(%esp)80487b4:e85ffeffffcall804861880487b9: 89 5c 24 04mov %ebx,0x4(%esp)80487bd: 89 04 24mov %eax,(%esp)80487c0: e8 f3 fd ff ffcall 80485b8 80487c5: c7 44 24 04 38 86 04 movl $0x8048638,0x4(%esp)80487cc: 0880487cd: 89 04 24mov %eax,(%esp)80487d0: e8 53 fe

22、 ff ffcall 8048628 /这些行就是执行 coutref = ref, i = iendl;80487d5: b8 00 00 00 00 mov $0x0,%eax80487da: 83 c4 28add $0x28,%esppop %ebx80487dd: 5b80487de: 5epop %esi80487df: 89 ec mov %ebp,%esp80487e1: 5dpop %ebp80487e2: c3ret从汇编代码可以看出实际上指针和引用在编译器中的实现是一样的:引用 int& ref=i;8048727: 8d 44 24 1c lea 0x1c(%esp),

23、%eax/ esp 寄存器里的变量 i 的地址传给 eax804872b: 89 44 24 18 mov %eax,0X 18(%esp)/将寄存器eax中的内容(i的地址)传给寄存器 中的变量ref,即int& ref=i指针 int* p=&i;8048777: 8d 44 24 1c lea 0x1c(%esp),%eax/ esp 寄存器里的变量 i 的地址传给 eax804877b: 89 44 24 10 mov %eax,0 X 10(%esp) /将寄存器eax中的内容(即i的地址)传到寄 存器esp中的p虽然指针和引用最终在编译中的实现是一样的,但是引用的形式大大方便了使用

24、也更安 全。有人说:”引用只是一个别名,不会占内存空间? ”通过这个事实我们可以揭穿这个谎 言!实际上引用也是占内存空间的。5、指针传递和引用传递为了更好的理解指针和引用,我们下面来介绍一下指针传递和引用传递。当指针和引用作为 函数的函数是如何传值的呢?(下面这一段引用了 C+中引用传递与指针传递区别(进一步 整理)指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调 函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函 数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的 任何操作都是作为局部变量进行,不会影响主调

25、函数的实参变量的值。引用传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这 时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成 间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形 参做的任何操作都影响了主调函数中的实参变量。引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但 是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。 而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变 量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针, 或者指针引用。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号