# 指针 指针(pointer)“指向(point to)“另外一种类型的复合类型。与引用类似,指针也实现了对其它对象的间接访问。 指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。 指针无需在定义时赋初值。在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。 `int *p1, p2;` //p1和p2都是指向int型对象的指针 `double dp, *dp2` //dp2都是指向double型对象的指针,dp是double型 ## 获取对象的地址 指针存放着某个对象的地址,想要获取该地址,需要使用取址符(操作符&): ```C++ int ival = 42; int *p = &ival; //p存放变量ival的地址,或者说p是指向ival的指针 ``` 因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。 ## 指针值 指针的值(即地址)应属于下列4种状态之一: 1. 指向一个对象 2. 指向紧邻对象所占空间的下一个位置。 3. 空指针,意味着指针没有指向任何对象。 4. 无效指针,也就是上述情况之外其他值。 试图拷贝或以其他方式访问无效指针的值都将引发错误。 ## 利用指针访问对象 如果一个指针指向了一个对象,则允许使用解引用符(操作符 *)来访问该对象: ```C++ int ival = 42; int *p = &ival; //p存放着变量ival的地址,或者说p是指向ival的指针 cout << *p << endl; //由符号*得到指针p所指的对象,输出42 ``` 对指针解引用会得出所指的对象,因此如果给解引用的结果赋值,实际上也就是给制作所指的对象赋值: ```C++ *p = 0; //由符号*得到指针p所指的对象,即可经由p为变量ival的赋值 cout << *p << endl; //输出0 ``` 为 *p 赋值实际上是为了 p 所指的对象赋值。 ## 空指针 空指针(null pointer)不指向任何对象,在试图使用一个指针代码可以首先检查它是否为空。以下列出几个生成空指针的方法: ```C++ int *p = nullptr; //等价于int *p = 0; int *p = 0; //直接将p2初始化为字面常量0 //首先需要 #include cstdlib int *p3 =NULL; //等价于int *p = 0; ``` 现在的C++程序最好使用nullptr,同时尽量避免使用NULL。 ## 赋值和指针 引用本身并非一个对象。一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象。 指针和它存放的地址之间就没有这种限制了。和其他任何变量(只要不是引用)一样,给指针赋值就是令它存放一个新的地址,从而指向一个新的对象: ```C++ int i = 42; int *pi = 0; //pi被初始化,没有指向任何对象 int *pi2 = &i; //pi2被初始化,存有i的地址 int *pi3; //如果pi3定义于块内,则pi3的值是无法确定的 pi3 = pi2; //pi3和pi2指向同一个对象i pi2 = 0; //现在pi2不指向任何对象了 ``` ## 其他指针操作 只要指针有一个合法值,就能将它用在条件表达式中。和采用算术值作为条件遵循的规则类似,如果指针的值是0,条件则取false: ```C++ int ival = 1024; int *pi = 0; //pi合法,是一个空指针 int *pi2 = &ival; //pi2是一个合法的指针,存放着ival的地址 if(pi) //pi的值是0,因此条件存放的值是false //.... if(pi2) //pi2指向ival,因此它的值不是0,条件的值是true //.... ``` 任何非0指针,对应的条件值都是true。 ## void* 指针 void*是一种特殊的指针类型,可以用于存放任意对象的地址。 ```C++ double obj = 3.14, *pd = &obj; //正确:void*能存放任意类型对象的地址 void *pv = &obj; //obj可以是任意类型的对象 pv = pd; //pv可以存放任意类型的指针 ``` 利用void* 指针能做的事比较有限:拿它和别的指针比较、作为函数的输入或输出,或者赋值给另一个void* 指针。不能直接操作void*指针所指的对象,因为我们并知道这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。 ## 指向指针的指针 通过* 的个数可以区分指针的级别。也就是说,**表示指向指针的指针,***表示指向指针的指针的指针,以此类推: ```C++ int ival = 1024; int *pi = &ival; //pi指向一个int型的数 int **ppi = π //ppi指向一个int型的指针 ``` 此处pi是指向int型数的指针,而ppi是指向int型指针的指针,下图描述了它们之间的关系。  解引用int型指针会得到一个int型的数,同样,解引用指向指针的指针会得到一个指针。此时为了访问最原始的那个对象,需要对指针的指针做两次解引用: ```C++ cout << "输出方式:\n" << "int类型输出:" << ival << "\n" << "指向ival的指针:" << *pi << "\n" << "指向指针的指针:" << **ppi << endl; ``` 该程序使用三种不同的方式输出了变量ival的值:第一种直接输出;第二种通过int型指针pi输出;第三种两次解引用ppi,取得ival的值。 ## 指向指针的引用 引用本不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用: ```C++ int i = 42; int *p; //p是一个int型指针 int &r = *p; //r是一个对指针p的引用 r = &i; //r引用了一个指针,因此给r赋值&i就是令p指向1 *r = 0; //解引用r得到i,也就是p指向的对象,将i的值改为0 ``` Loading... # 指针 指针(pointer)“指向(point to)“另外一种类型的复合类型。与引用类似,指针也实现了对其它对象的间接访问。 指针本身就是一个对象,<mark>允许</mark>对指针<mark>赋值和拷贝</mark>,而且在指针的生命周期内它可以先后指向几个不同的对象。 指针<mark>无需</mark>在定义时赋初值。在块作用域内定义的指针如果没有被初始化,也将拥有一个<mark>不确定的值</mark>。 `int *p1, p2;` //p1和p2都是指向int型对象的指针 `double dp, *dp2` //dp2都是指向double型对象的指针,dp是double型 ## 获取对象的地址 指针<mark>存放着某个对象的地址</mark>,想要获取该地址,需要使用<mark>取址符(操作符&)</mark>: ```C++ int ival = 42; int *p = &ival; //p存放变量ival的地址,或者说p是指向ival的指针 ``` 因为引用不是对象,<mark>没有实际地址</mark>,所以不能定义指向引用的指针。 ## 指针值 指针的值(即地址)应属于下列4种状态之一: 1. 指向一个对象 2. 指向紧邻对象所占空间的下一个位置。 3. 空指针,意味着指针没有指向任何对象。 4. 无效指针,也就是上述情况之外其他值。 试图拷贝或以其他方式访问无效指针的值都将引发错误。 ## 利用指针访问对象 如果一个指针指向了一个对象,则允许使用<mark>解引用符(操作符 *)</mark>来访问该对象: ```C++ int ival = 42; int *p = &ival; //p存放着变量ival的地址,或者说p是指向ival的指针 cout << *p << endl; //由符号*得到指针p所指的对象,输出42 ``` 对指针解引用会得出所指的对象,因此如果给解引用的结果赋值,实际上也就是给制作所指的对象赋值: ```C++ *p = 0; //由符号*得到指针p所指的对象,即可经由p为变量ival的赋值 cout << *p << endl; //输出0 ``` 为 *p 赋值实际上是为了 p 所指的对象赋值。 ## 空指针 空指针(null pointer)不指向任何对象,在试图使用一个指针代码可以首先检查它是否为空。以下列出几个生成空指针的方法: ```C++ int *p = nullptr; //等价于int *p = 0; int *p = 0; //直接将p2初始化为字面常量0 //首先需要 #include cstdlib int *p3 =NULL; //等价于int *p = 0; ``` 现在的C++程序最好使用nullptr,同时尽量避免使用NULL。 ## 赋值和指针 引用本身并非一个对象。一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象。 指针和它存放的地址之间就没有这种限制了。和其他任何变量(只要不是引用)一样,给指针赋值就是令它存放一个新的地址,从而指向一个新的对象: ```C++ int i = 42; int *pi = 0; //pi被初始化,没有指向任何对象 int *pi2 = &i; //pi2被初始化,存有i的地址 int *pi3; //如果pi3定义于块内,则pi3的值是无法确定的 pi3 = pi2; //pi3和pi2指向同一个对象i pi2 = 0; //现在pi2不指向任何对象了 ``` ## 其他指针操作 只要指针有一个合法值,就能将它用在条件表达式中。和采用算术值作为条件遵循的规则类似,如果指针的值是0,条件则取false: ```C++ int ival = 1024; int *pi = 0; //pi合法,是一个空指针 int *pi2 = &ival; //pi2是一个合法的指针,存放着ival的地址 if(pi) //pi的值是0,因此条件存放的值是false //.... if(pi2) //pi2指向ival,因此它的值不是0,条件的值是true //.... ``` <mark>任何非0指针,对应的条件值都是true。</mark> ## void* 指针 void*是一种特殊的指针类型,可以用于存放<mark>任意对象</mark>的地址。 ```C++ double obj = 3.14, *pd = &obj; //正确:void*能存放任意类型对象的地址 void *pv = &obj; //obj可以是任意类型的对象 pv = pd; //pv可以存放任意类型的指针 ``` 利用void* 指针能做的事比较有限:拿它和别的指针比较、作为函数的输入或输出,或者赋值给另一个void* 指针。不能直接操作void*指针所指的对象,因为我们并知道这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。 ## 指向指针的指针 通过* 的个数可以区分指针的级别。也就是说,**表示指向指针的指针,***表示指向指针的指针的指针,以此类推: ```C++ int ival = 1024; int *pi = &ival; //pi指向一个int型的数 int **ppi = π //ppi指向一个int型的指针 ``` 此处pi是指向int型数的指针,而ppi是指向int型指针的指针,下图描述了它们之间的关系。  解引用int型指针会得到一个int型的数,同样,解引用指向指针的指针会得到一个指针。此时为了访问最原始的那个对象,需要对指针的指针做两次解引用: ```C++ cout << "输出方式:\n" << "int类型输出:" << ival << "\n" << "指向ival的指针:" << *pi << "\n" << "指向指针的指针:" << **ppi << endl; ``` 该程序使用三种不同的方式输出了变量ival的值:第一种直接输出;第二种通过int型指针pi输出;第三种两次解引用ppi,取得ival的值。 ## 指向指针的引用 引用本不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用: ```C++ int i = 42; int *p; //p是一个int型指针 int &r = *p; //r是一个对指针p的引用 r = &i; //r引用了一个指针,因此给r赋值&i就是令p指向1 *r = 0; //解引用r得到i,也就是p指向的对象,将i的值改为0 ``` 最后修改:2024 年 03 月 17 日 © 允许规范转载 打赏 赞赏作者 支付宝 赞 如果觉得我的文章对你有用,请随意赞赏
80 条评论
家族史之谜埋葬的过去
生于一九四七爱情仍在继续
乜代宗师粤配
战锋尖峰对决
狄仁杰之天神下凡
康奈尔之盒
最强壮的人
java教程
超級鯊魚大道港
环游地球八十天
美丽的习惯
乐一通大电影地球爆炸之日
五郎八卦棍粤配
塞伦盖蒂第三季
跨过鸭绿江
凶杀重案实录纽约
环游地球八十天
世界上最好的
寻宝搭档圣诞特别篇
新大头儿子和小头爸爸之秘密计划
来聊聊须绪美吧
好莱坞圣诞
米尔斯探秘生态中国
卡萨托里亚
从海底出击
ktv火热的女人2
迷途的羔羊
与神同行2因与缘
少女不毕业
泰坦尼克号
孤胆追踪者
拿针的女孩
雪豹之虎啸军魂
没有屋顶的房子
搭秋千的人
全能的宙斯
好像也没那么热血沸腾
你们见到的还不算什么
狂暴3击倒总统
杀死托尼笑不死偿命
米克与诡计
开心超人之逆世营救
圣帕特里克的驱魔
唐人街制造
成为齐柏林飞艇
超人明日之子
超危险保镖
亚洲犯罪网
地道战1965
米歇尔布托美丽真心话
恶魔娜塔丽
亚瑟的威士忌
六月里来好阳光
最后一根稻草
无国界牛仔
超危险保镖
克雷格费格森我超开心
再见金钱前往贫困村
理发师陶德
白头神探智斗灭世狂人
霍元甲之精武天下
百万小宝贝
我是狼之火龙山大冒险
好莱坞圣诞
帕洛玛之旅
新假面骑士
芝加哥七君子审判
寻宝搭档圣诞特别篇
长生不死硅谷富豪的逆龄人生
谍影重重4
聊斋之极道天师
时间的守护者
你们见到的还不算什么
恶行之外粤配
喋血双雄粤配
战锋尖峰对决
我们的追星之路
怪物大乱捣
段落衔接自然,过渡流畅,读来一气呵成。
对话设计自然,符合角色身份与情境。