指向常量的指针
指向常量的指针,即
pointer to const
,即指针指向的是一个常量,你应该把这个词(指向常量的指针)当做一个整体来理解,而不是分开。(当然也有翻译成指针常量的,但我并不喜欢这种翻译方式)
1
通常也将指针本身是一个常量称为顶层 const,将指针所指的对象是个常量称为底层 const
它的语法格式是 const
在 *
左边,这一点很重要,因为后面要讲的常量指针是 const
在 *
的右边。下面是它的基本语法格式
1 | const double pi = 3.14; // pi 是一个常量 |
下面我们举一个例子来进行具体的讲解 1
2
3
4
5
6
7
8
9
10
using namespace std;
int main()
{
const double pi = 3.14; // pi 是一个常量
const double *cptr = π // cptr 是一个指向常量的指针
cout << *cptr << endl; // 3.14
return 0;
}1
2
3
4
5 const double pi = 3.14; // pi 是一个常量
double *pnormal = π // 用普通指针指向常量 pi
// error: invalid conversion from ‘const double*’ to ‘double*’
return 0;
答案显然是不行的,报错提示这是一个非法类型转换。
事实上,有这样的一个指向关系,指向常量的指针可以指向常量和非常量,而普通指针只能指向非常量,如下图所示。
对上图,从逻辑上是这么理解的,假设一个普通指针
common_pointer
指向且只能指向非常量
non_const_var
,通过对 common_pointer
的解引用,我们可以修改非常量 non_const_var
的值。但是如果普通指针 common_pointer
指向一个常量
const_var
,理论上来说,可以对普通指针
common_pointer
解引用而修改常量 const_var
的值,但常量又不能修改,所以普通指针只能指向非常量。
对于常量指针的逻辑亦是如此。 那么第二个问题是,cptr
指针指向的内容可以修改吗?显然也是不能修改的,因为它此时指向的是一个常量
1
2
3
4
5const double pi = 3.14; // pi 是一个常量
const double *cptr = π // cptr 是一个指向常量的指针
cout << *cptr << endl; // 3.14
*cptr = 9.8; // error: assignment of read-only location ‘* cptr’
return 0;cptr
具有只读属性。特别的是,即使 cptr
指向的是非常量,它也不能修改这个非常量的内容(如下代码),仅记住一点即可,那就是
cptr
自己本身具有的属性就是只读的。 1
2
3
4double pi = 3.14; // pi 是一个变量
const double *cptr = π // cptr 是一个指向常量的指针
cout << *cptr << endl; // 3.14
*cptr = 9.8; // error: assignment of read-only location ‘* cptr’1
2
3
4
5
6
7
8
9
10
11
12
using namespace std;
int main()
{
int b = 10;
int c = 20;
const int* a = &b;
cout << *a << endl; // 10
a = &c;
cout << *a << endl; // 20
}char *const p = greeting;
下面我们用一张图来解释什么叫“指针的值(指针本身的内容)不能被修改”
虽然这幅图已经说明了一切,但我们还是不妨用代码来进一步解释 1
2
3
4
5
6
7
8
9
10
11
12
using namespace std;
int main()
{
double pi = 3.14; // pi 是一个变量
double e = 2.71; // e 是一个变量
double *const cptr = π // cptr 本身的内容不能改变
cout << *cptr << endl; // 3.14
cptr = &e; // error: assignment of read-only variable ‘cptr’
return 0;
}
但是 cptr 指向的内容却是可以改变的,这和
pointer to const
不同 1
2
3
4
5
6double pi = 3.14; // pi 是一个变量
double e = 2.71; // e 是一个变量
double *const cptr = π // cptr 本身的内容不能改变
cout << *cptr << endl; // 3.14
*cptr = e;
cout << *cptr << endl; // 2.71
对比指向常量的指针与常量指针
也许直接记忆中文的话会很容易绕进去,不如直接记忆它们各自对应的英文会要很多,即指向常量的指针是
pointer to const
,常量指针是
const pointer
。
对于 pointer to const
来说,显然指针指向的是一个常量(当然它也可以指向一个非常量),对于
const pointer
来说,显然它自己是一个常量,即这个指针是一个常量,它蕴含的意思是这个指针指向的地址永远不可以改变,就好像你永远住在
xx 省 xx 市 xx 路 xx 号一样。
最后还是用一幅图来解释二者的联系与区别 红色区域是不能改变的值。
【注】在这幅图中,如果我们把 pi 改为非常量,即
double pi = 3.14
; 的形式,虽然依旧不能通过 cptr
来修改它的值,如 *cptr = 2.71 // error
,但是可以直接修改 pi
的值是没问题的,如
pi = 2.71; // right
。这一点我已经在上面的部分讲过,但在这里还想重复提一下。
1
2
3
4
5
6
7
8
9
10
11
12
13
using namespace std;
int main()
{
double pi = 3.14;
const double *cptr = π
cout << *cptr << endl; // 3.14
// *cptr = 2.71; error
pi = 2.71;
cout << *cptr << endl; // 2.71
return 0;
}1
2
3
4
5
6
7
8
9int main()
{
char c = 'c';
char* pc;
pc = &c;
const char** pcc = &pc;
return 0;
}const char** pcc = &pc;
位置会报错
error: invalid conversion from ‘char**’ to ‘const char**’
。原因是,我们的二重指针是
const
的,当 pcc 通过 pc 指向 c 后,逻辑上,我们不希望通过
pcc 来改变 c,但是,pcc 在指向 pc 的时候,pc 不是 const 的,意味着 pc
可以随时改变指针的指向。
上面的代码将 pc 设置为 const 就可以正常运行了
1 | int main() |