1.指向指针的指针
int ival = 1024; int *pi = &ival; //pi指向一个int型的数 int **pi = *pi; //ppi 指向一个int型的指针
2.解引用int型指针会得到一个int型的数,同样解引用指向指针的指针,会得到一个指针。此时为了访问最原始的那个对象,需要对指针的指针做两次解引用。
std::cout << "The value of ival" << std::endl; std::cout << "Direct value" << ival << std::endl; std::cout << "indirect value" << *pi << std::endl; std::cout << "doubly indirect value" << **ppi << std::endl;
该程序通过三种不同的方式输出了变量ival的值:第一次是直接输出ival;第二次是通过一次int型指针pi的输出;第三次是通过两次解引用ppi,取得ival的值。
3.指向指针的引用
引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在指针的引用:
int i= 42;
int *p; //p是一个int型的指针
int *&r = p; //r是一个指针p的引用
r = &i; // r 引用了一个指针,因此给 r 赋值 &i 就是令 p 指向 i ;
*r = 0; //解引用 r 得到 i ,也就是 p 指向的对象,将 i 的值改为 0;
tip:
面对一条比较复杂的指针或引用的声明语句时,从右向左阅读有助于理清它真正的含义。
const限定符:
有时候我们希望可以定义这样一种变量,它的值不能被改变。例如,用一个变量来表示缓冲区的大小。使用变量的好处是当我们觉得缓冲区大小不再合适时,很容易对其进行调整。另一方面,也应随时警惕防止程序不小心改变了这个值。为了满足这一要求,可以用const 关键字对变量的类型加以限定。
const int bufSize = 512; //输入缓冲区大小
这样就把bufSize定义成了一个常量。任何试图为bufSize赋值的行为都将引发错误;
bufSize = 512; //错误:试图向const对象写值
因为const对象一旦创建后其值就不再被改变,所以const对象必须初始化。一如既往,初始值可以是任意复杂的表达式。
const int i = get_size(); //正确:运行时初始化 const int j = 42; //正确:编译时初始化 const int K; //错误:k是一个未经初始化的常量
初始化和const
在不改变const对象的操作中还有一种是初始化,如果利用一个对象去初始化另外对象,则它们是不是const都无关紧要。
int i = 098; const int ci = i; //正确:i的值被拷贝给了ci int j = ci ; //正确:ci的值被拷贝给了j
默认状态下,const对象仅在文件内有效
const int bufSize = 512; //输入缓冲区大小
//file_1.cc 定义并初始化了一个常量,该常量能被其他文件访问
extern const int bufSize = fcn();
//file_1.h 头文件
extern const int bufSize; //与file_1.cc中定义的bufSize是同一个
如果想在多个文件之间共享const 对象,必须在变量的定义之前添加extern关键字
练习:下面哪些句子是合法的?如果有不合法的句子,请说明为什么?
(a)const int buf; (c)const int sz =cnt;
(b)int ent=0; (d)++cnt; ++sz;(a)和(d)是合法的。(b)和(c)是不合法的。
(a)是合法的,因为它声明了一个常量整数变量buf,但是没有对其进行初始化。
(b)是不合法的,因为它声明了一个整数变量ent并试图将其初始化为0,但是缺少关键字const。如果将句子(b)中的int ent=0;改为const int ent=0;则句子(b)也是合法的。
(c)是不合法的,因为它试图将一个非const变量cnt赋值给const变量sz,这是不允许的。如果要将一个非const变量赋值给const变量,必须使用初始化方式进行声明,例如:const int sz = cnt;而不是const int sz = cnt;
(d)是合法的,因为它试图递增两个变量cnt和sz的值。