C++变量和基本类型3--复合类型

   复合类型是指基于其他类型定义的类型,C++有几种复合类型,本章主要介绍引用和指针。

1.引用

   引用为对象起了另一个名字,引用类型引用另外一种类型。通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量。

int i=1024;
int &iref = i;//iref是i的引用
int &iref2; //错误,引用必须初始化

   一般在初始化时,初始化值会被拷贝都新建对象中。然而定义引用时,程序把引用和它的初始化值绑定在一起,而不是将初始化值拷贝给引用。一旦引用初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到新的对象上,因此引用必须初始化。

2.指针

   与引用类似,指针也实现了对其他对象的间接访问。与引用不同的是,其一,指针本身也是对象,允许对指针赋值和拷贝,而且在指针的声明周期内它可以先后指向几个不同的对象。其二,指针无线在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
定义指针类型的方法将声明写成*d,其中d是变量名。如果在一条语句中定义了几个指针变量,每个变量前面都必须有符号星号:

int *ip1, *ip2 //ip1和ip2都是指向int对象的指针
double dp1, *dp2 //dp1是double对象,dp2是指向double类型对象的指针

获取对象的地址
   指针存放某个对象的地址,要想获取该地址,需要使用取地址符&

int ival = 42;
int *p = &ival; //p存放变量ival的地址

指针的类型要和它指向的对象严格匹配:

double dval;
double *pd = &dval //正确,类型匹配
double *pd2 = pd; //正确,类型匹配

int *pi = pd; //错误:指针pi的类型和pd的类型不匹配
pi = &dval;   //错误,视图是double对象的地址赋给int型指针

   指针值有下列四种状态之一:
指向一个对象
指向紧邻对象所占空间的下一个位置
空指针,意味着指针没有指向如何对象
无效指针,也就是上述情况之外的其他值

利用指针访问对象
   如果指针指向了一个对象,则允许使用解引用符*来访问改对象:

int ival = 42;
int *p = ival;
std::cout << *p << std::endl;

空指针
   空指针不指向任何对象,在试图使用一个指针之前代码可以首先检查它是否为空。以下列出几个生成空指针的方法:

int *p1 = nullptr; //c++11 新标准引入的方法
int *p2 = 0;       //直接将p2初始化为字面值常量0
int *p3 = NULL;    //预处理变量,定义在cstdlib中,它的值是0

   当用到一个预处理变量时,预处理器会自动将它替换为实际值,因此使用NULL和使用0初始化指针是一样的。在新的标准下,现在C++程序最好使用nullptr,同时尽量避免使用NULL。

建议初始化所有指针
   使用未经初始化的指针是引发运行时错误的一大原因,通常会造成程序奔溃。因此建议初始化所有的指针,并且在可能的情况下,尽量等定义了对象之后再定义指向它的指针。如果实在不清楚指针应该指向何处,就把它初始化为nullptr,这样程序就能检测并知道它没有指向任何具体的对象了。

3.理解符合类型的声明

定义对个变量
   经常有一种错误的观点误以为,在定义语句中,类型修饰符(*或者&)作用于本次定义的全部变量。造成这种错误看法的原因很多,其中之一是我们可以把空格写在类型修饰符和变量名中间:

int* p;   //合法,但是容易产生误导

   我们说这种写法可能产生误导是因为int放在一起好像是这条语句中所有的变量共同的类型一样。其实恰恰相反,基本数据类型是int而非int。*仅仅是修饰了p而已,对该声明语句的其他变量,它并不产生任何作用。

int* p1, p2; //p1是指向int的指针,p2是int

   涉及指针或者引用的声明,一般有两种写法。第一种把修饰符和变量标识符写在一起:

int *p1, *p2; //p1,p2都是指向int的指针

   这种形式着重强调变量具有的复合类型。第二种把修饰符和类型名写在一起,并且每条语句只定义一个变量:

int* p1; //p1是指向int的指针
int* p2; //p2是指向int的指针

   这种形式着重强调本次声明定义了一种复合类型。
   上述两种定义指针或者引用的不同方法每一天孰对孰错之分,关键是选择并坚持其中一种写法,不要总是变来变去。

指向指针的指针
   一般来说修饰符的个数并没有限制。当有多个修饰符连在一起写时,按照其逻辑关系解释即可。以指针为例,指针是内存中的对象,像其他对象一样也有自己的地址,因此允许把指针的地址再存放到另一个指针当中。通过*的个数可以区分指针的级别。也就是说,**表示指向指针的指针,***表示指向指针的指针的指针,一次类推。

int ival =1024;
int *pi = &ival; //pi指向一个int的数
int **ppi =&pi;  //ppi指向一个int的指针

指向指针的引用
   引用本身不是一个对象,因此不能定义指向引用的指针。但是指针是对象,所以存在对指针的引用:

int i = 42;
int *p;  //p是一个int型指针
int *&r = p;  // r是一个对指针p的引用

r = &i; //r引用了一个指针,因此给r赋值&r就是令p指向i
*r = 0; //解引用r得到i,也就是p指向的对象,将i的值改为0

   要理解r的类型到达是什么,最简单的办法就是从右往左阅读r的定义。离变量名最近的符号(此例中是&r的符号&)对变量的类型有最直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么,此例中的符号*说明r引用的是一个指针。最后,声明的基本数据类型部分指出r引用的是一个int指针。
面对一条比较复杂的指针或者引用的声明语句时,从右往左阅读有助于弄清它的真是含义。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值