这几天看C++的指针,刚开始的时候还算清楚,看到指向指针的指针这一块的时候就不淡定了。现假设p为指向指针的指针,看看下面的一堆东西。
p &p *p (void *)*p **p *p+1 *(p+1) **p+1 **(p+1) 这些东西都代表啥意思呢?输出是怎样的?为什么会这样?做个试验看看吧。
试验代码如下:
#include<iostream>
using namespace std;
int main(){
char *test[]={"my","name","is","sunnix"};//声明一个指针数组
char **p=test;//声明一个指向指针的指针
cout<<"p="<<"\t"<<p<<endl
<<"&p="<<"\t"<<&p<<endl
<<"*p="<<"\t"<<*p<<endl
<<"(void *)*p="<<"\t"<<(void *)*p<<endl
<<"**p="<<"\t"<<**p<<endl
<<"*p+1="<<"\t"<<*p+1<<endl
<<"*(p+1)="<<"\t"<<*(p+1)<<endl
<<"**p+1="<<"\t"<<**p+1<<endl
<<"**(p+1)="<<"\t"<<**(p+1)<<endl;
}
先看看输出结果:
这个时候就应该问问为什么了。
第一句非常好理解,p为指向指针的指针,不管他指向什么,说到底还是指针,那么他当中存放的就是地址,只不过这个地址是另一个指针的地址。在本例当中这个另一个指针就是指向字符串“my”首地址的指针。
第二句也非常好理解,p当中不管保存的是什么,本身是要占用内存的,“&”为地址运算符,那么&p就是p本身在内存当中的地址。
第三句很奇怪,p是一个指向指针的指针,那么“*”为间接引用运算符,返回的是指针所指向的对象,本例中他指向一个指针,那么取出的不应该是p所指向的指针中保存的地址么?我的理解是这样的,p为指向指针的指针,*p取出的是他所指向的指针中保存的地址,在本例当中这个地址就是下一句输出的地址01027894,系统取到这个地址以后,发现这个地址中保存的是字符型的,所以cout会输出这些字符,直到遇到‘\0’结束输出,所以本例当中输出了“my”。
第四句,将*p的类型进行强制转换,转成通用型的指针类型,这时候输出的是这个指针所指向的地址。
第五句,p是一个指向指针的指针,那么p指向一个指针,进行*p运算以后,*p就不再指向一个指针,而是指向一个具体的对象,**p就相当于*(*p)运算,这时,返回的就是*p所指向的具体的对象。在本例当中,指向的就是m这个字符。我自己理解的p、*p和**p的区别。p和*p都是指针,而**p是*p所指向的具体的对象。输出时p和*p都表示的是一个地址,只不过*p所指向的地址保存的是字符串,cout语句会将这些字符串输出,直到遇到‘\0’结束符。
第六句,*p+1由于“*”的优先级高于“+”,所以先进行*p运算,*p依然是一个指针,指向字符串“my”的首地址,“+1”运算以后就指向了“y”,此时会将“y”后面的字符串输出,只是本例中“y”已经结束,所以只输出了“y”,假设“y”后面还有字符串“abc”,那么输出就是“yabc”。
第七句,*(p+1)因为"()"优先级高于"*",先进行p+1运算,p+1同样为一个指向指针的指针,+1运算完成后会指向下一个指针,再进行“*”运算以后,指向这个指针指向的对象,本例中指向了“name”的首地址,然后输出“name”。“*p+1”和“*(p+1)”的区别就在于前者先取对象,再移动指针。后者先移动指针,再取指针所指的对象。因为p指向一个指针数组,所以后者的操作是合法的。
第八句,**p+1,**P已经不是一个指针,而是一个具体的对象,本例中为字母“m”,再进行“+1”运算,是将字母“m”的ASCII值和1相加,所以得到110。
第九句,**(p+1),此时先进行指针的移动运算,移动后*(p+1)指向了“name”的首地址,再进行**(p+1)运算,取出这个首地址中的对象,即字符“n”,进行输出。
最后,水平有限,有理解不到位的地方欢迎指出,说法不正确或者不专业的地方也欢迎指出。