2.3.1 引用
主要概念
- 引用(reference) 为对象起了另外一个名字,引用类型引用(refers to)另外一种类型。
- 通过在声明符前加
&
的形式为定义引用类型,例如:
int ival = 1024;
int &refVal = ival;
int &refVal2;//这一行会报错,在声明引用时必须初始化
- 定义引用时必须初始化引用,并且一旦初始化引用,引用将永远和它的初始值永远绑定在一起。注意!仅声明而不定义时可以不初始化!
- 引用本质上是一个变量的别名,因此初始化时也必须与一个变量绑定。
- 引用类型必须和与它绑定的类型严格匹配(仅有两种例外)。
练习
- 练习2.15 下面的哪个定义是不合法的?为什么?
int ival = 1.01; //普通的整型变量定义,可以通过编译,但会丢失小数部分的值
int &rval1 = 1.01; //不合法,引用类型必须用一个变量进行绑定。
int &rval2 = ival; //合法
int & rval3; //不合法,引用声明时必须初始化
- 练习2.16 考查下面的所有赋值然后回答 :哪些赋值是不合法的?为什么?哪些赋值是合法的?它们执行了什么样的操作?
int i= 0,&r1 = i;
double d = 0,&r2 = d;
----
(a)r2 = 3.14159; //合法,操作等价于将d赋值
(b)r2 = r1 ;//合法,将r1引用的值赋给r2引用的值
(c)i = r2;//合法,将r2的值赋给i
(d)r1 = d;//合法,将d的值赋给r1引用的值
- 练习2.17 执行下面的代码段将输出什么结果?
int i = 0, &ri = i;
i = 5;
ri = 10;
cout << i << " " << ri << endl;
答:由于ri是对i的引用,所以ri赋值等于i赋值,取值也是一样,所以最后输出:
10 10
2.3.2 指针
主要概念
- 指针(pointer)是指向(point to)另外一种类型的复合类型,与引用类似地,也实现了对其他对象的间接访问。
- 指针本身就是一个对象,可以进行赋值和拷贝。
- 指针不需要在定义时赋值,与其他内置类型一样,如果没有被初始化,将拥有一个不确定的值 。
- 指针的声明符写成
*d
的形式,如果在一条语句中定义了多个指针变量,每个变量前都必须有符号*
。 - 获取对象的地址要使用取地址符
&
,例如:
int ival = 42;
int *p = &ival;
- 与引用类似,除了两种例外情况外,其他所有的指针的类型都必须跟它指向的对象严格匹配。
- 指针的值其实是某个对象的地址,它可能有四种状态:指向一个对象、指向紧邻对象所占空间的下一个位置 、空指针 、无效指针。
- 利用解引用符可以访问该对象,注意!解引用符使用时一定要确定引用了有效的位置。
int ival = 42;
int *p = &ival;
*p = 0; //可以将ival的值变为0
cout << *p;//输出ival的值
- 空指针(null pointer)不指向任何对象,在试图使用一个指针之前,代码可以首先检查它是否为空。使一个指针的值变为空指针有以下三个常用方法:
int *p;
p = nullptr;
p = 0;
p = NULL;
- 建议初始化所有指针。
void*
指针可以用于存放任意对象的地址,即可以表示任意对象的指针。
练习
- 练习2.18:编写代码分别更改指针的值 以及指针所指对象的值。
//很明显,考察的是对指针引用的理解
int i = 1 , j= -1;
int *p = &i;
p = &j;//修改指针的值
*p = 0;//修改指针所指的对象的值
- 练习2.19 说明指针和引用的主要区别
答:
1.指针是对一个对象的地址的引用,可以通过访问地址来访问一个对象,而引用的本质是一个对象的别名。
2.指针可以多次修改引用的对象,而引用不可更改对象。
3.指针在初始化时可以不进行显式初始化,引用必须显示初始化。
- 练习2.10 请叙述下面这段代码的作用。
int i = 42; //定义变量i并初始化值为42
int *pl = &i;//定义变量pl并初始化指向i
*pl = *pl * *pl;//通过指针pl访问i获取i的值,将i的值进行平方后再通过pl访问对i进行赋值
- 练习2.21 请解释下述定义。在这些定义 有非法的吗?如果有,为什么?
int i = 0;
double* dp = &i; //非法,指针类型必须匹配
int *ip = i;//合法,但是可能没有意义
int *p = &i;//合法
- 练习2.22:假设p是一个int型指针,请说明下述代码的含义
if(p) // 如果p不为空指针
if(*p) //如果p指向的值不为0
- 练习2.23 给定指针p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断的思路;如果不能,请说明原因。
答:
不能知道是否指向一个合法的对象,需要更多的信息。
因为指针有四种可能的状态,其中有三种情况可能不合法:
1.如果是空指针,那么必然是不合法的对象;
2.如果是指向紧邻对象的下一个位置,比如一个数组的最后一个对象之后的内存,那么它不是空指针,但也不一定合法。
3.如果是无效指针,比如一个有值但未初始化的指针,这可能造成不可测的后果。
- 练习2.24:在下面这段代码 中为什么 p合法而lp非法?
int i = 42;
void *p = &i;
long *lp = &i;//指针类型必须严格匹配
2.3.3 理解复合类型的声明
主要概念
*
是一个修饰符,可以重复使用,例如可以产生指向指针的指针。&
也是一个修饰符,可以产生对一个对象的引用,由于指针也是对象,所以可以产生对指针的引用;同样的,由于引用不是一个对象,所以不能产生对引用的引用。- 面对一条复杂的指针或引用的声明语句时,可以尝试从右向左阅读,这有助于弄清楚它的真实含义。
练习
练习2.25: 说明下列变量的类型和值
int* ip,i, &r = i; //声明int型的指针ip,int型的变量i,Int型的引用变量i的引用r。
int i,*ip =0;//声明int型的变量i,int型的指针ip并初始化它的值为0
int* ip, ip2; //声明int型的指针ip,int型的变量ip2