# 指针 指针(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 日 © 允许规范转载 打赏 赞赏作者 支付宝 赞 如果觉得我的文章对你有用,请随意赞赏
38 条评论
圣帕特里克的驱魔
唐人街制造
成为齐柏林飞艇
超人明日之子
超危险保镖
亚洲犯罪网
地道战1965
米歇尔布托美丽真心话
恶魔娜塔丽
亚瑟的威士忌
六月里来好阳光
最后一根稻草
无国界牛仔
超危险保镖
克雷格费格森我超开心
再见金钱前往贫困村
理发师陶德
白头神探智斗灭世狂人
霍元甲之精武天下
百万小宝贝
我是狼之火龙山大冒险
好莱坞圣诞
帕洛玛之旅
新假面骑士
芝加哥七君子审判
寻宝搭档圣诞特别篇
长生不死硅谷富豪的逆龄人生
谍影重重4
聊斋之极道天师
时间的守护者
你们见到的还不算什么
恶行之外粤配
喋血双雄粤配
战锋尖峰对决
我们的追星之路
怪物大乱捣
段落衔接自然,过渡流畅,读来一气呵成。
对话设计自然,符合角色身份与情境。