变量的定义包括一个基本数据类型和一组声明符。在同一条定义语句中,虽然基本数据类型只有一个,但是声明符的形式却可以不同。也就是说,一条定义语句可能定义不同类型的变量:
int i=1024, *p=&i, &r=i;//i是一个int型的数,p是一个int型指针,r是一个int型引用
定义多个变量
经常有一种观点会误以为,在定义语句中,类型修饰符(*或&)作用于本次定义的全部变量。造成这种误解的原因有很多,其一便是我们可以吧空格写在类型修饰符和变量名中间:
int* p;//合法但容易引起误导
我们说这种写法可能引起误导是因为int*放在一起好像是这条语句中所有变量共同的类型一样。其实恰恰相反,基本数据类型是int而非int*。*仅仅是修饰了p而已,对该声明语句中的其他变量,它并不产生任何作用:
int* p1,p2;//p1是指向int型的指针,p2是int
涉及指针或引用的声明,一般写法有两种。第一种把修饰符和变量标识符写在一起:
int *p1,*p2;//p1和p2都是指向int型的指针
这种形式着重强调变量具有的复合类型。第二种把修饰符和类型名写在一起,并且每条语句只定义一个变量:
int* p1;
int* p2;
这种形式着重强调本次声明定义了一种复合类型。
指向指针的指针
一般来说声明符中修饰符的个数没有限制。当有多个修饰符连写在一起时,按照其逻辑关系详加解释即可。以指针为例,指针是内存中的对象,像其他对象一样也有自己的地址,因此允许把指针的地址再存放到另一个指针当中。
通过*的个数可以区分指针的级别。也就是说,**表示指向指针的指针,****表示指向指针的指针的指针,以此类推:
int val =1024;
int *p=&val;
int **q=&p;//q是指向p指针的指针
解引用int 型指针会得到一个int型的数,同样解引用指向指针的指针会得到一个指针。此时为了访问最原始的那个对象,需要对指针的指针做两次解引用:
cout<<"The value of val \n"
<<"direct value :"<<val<<"\n"
<<"indirect value:"<<*p<<"\n"
<<"doubly indirect value:"<<**q<<endl;
该程序使用三种不同的方式输出了变量val的值,第一种直接输出;第二种通过int型指针p输出;第三种两次解引用q,取得val的值
指向指针的引用
引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用:
int i=42;
int *p;
int *&r=p;//r是一个对指针p的引用
r=&i;r引用了一个指针,因此给r赋值&i就是令p指向i
*r=0;//解引用r得到i,也就是p指向的对象,将i的值改为0
要理解r的类型到底是什么,最简单的方法是从右往左阅读r的定义。离变量名最近的符号对变量的类型有最直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么,此例中的符号*说明r引用的是一个指针。最后,声明的基本数据类型部分指出r引用的是一个int 指针。
tip:面对一条比较复杂的指针或引用的声明语句时,从右往左阅读有助于弄清楚它的真实含义。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步