ChristmasError-Blog

C++中const的“就近原则”

字数统计: 942阅读时长: 3 min
2018/10/18 Share

在做题的时候,编译时经常会遇到关于const的坑,如果在平时不是常用的话就会很容易忘记,在这里整理一下const的“就近原则”的笔记。

指针

要理解就近原则首先要明白指针。
指针(pointer),可以看作指向(point to)。与引用类似,实现了对其他对象的间接访问。
但有两个不同之处:
1.指针本身就是一个对象,允许对指针赋值和拷贝,并且指针在周期内可以先后指向几个不同的对象(除非是const指针)

const指针是指针变量的值一经初始化,就不可以改变指向,初始化是必要的。其定义形式如下:
int * const pTwo; //指向整形的常量指针 ,它不能在指向别的变量,但指向(变量)的值可以修改。(结合之后会说的就近原则理解记忆。)

2.指针无需在定义时赋初值(若未初始化,它将有一个不确定得值)。

简单示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
int a = 0;
int b = 1;

int* const p1 = &a; //p1是指向int型数据的const指针,指向不可改变。
int* (const p11) = &a; //p11与p1相同。
const int *p2 = &a; //p2是指向int型数据的指针,指向可以改变,
//但不可以通过p2改变指向地址上的值。
const int(*p22) = &a; //p22与p2相同。
const int* const p3 = &a; //p3是指向in型数据的const指针,不能通过p3改变指向地址上的值。
p1 = &b; //报错(指针指向不能被修改)
*p1 = b;
p2 = &b;
*p2 = b; //报错(指针指向的内容不能被修改)
p22 = &b;
*p22 = b; //报错(指针指向的内容不能被修改)
p3 = &b; //报错(指针指向不能被修改且指针指向的内容不能被修改)
*p3 = b; //报错
}

读const指针的方法,我们可以学习《C++Primer》上 P56的方法,也就是“从右往左读”。

1
2
3
4
int errNumb =0;
int *const curErr = &errNumb;
const double pi = 3.1415;
const double *const pip = π

此例中,从右往左,离curErr最近的是const,意味着curErr本身是一个常量对象,继续往左看,下一个符号*和int表明curErr是一个指向int类型的指针——结合起来curErr就是一个常量指针,指向不可变,但可通过其本身改变指向地址上的值。
指针pip同理,可以得知:pip是一个指向const double的const指针,指向和指向地址上的值不可变。

const* ———————————修饰指针
const int*——————const修饰指针指向的对象, int * const

就近原则

就近原则我们可以在K & R 《The C Programming Language》(2nd)

A.8.6.1 Pointer Declarators

In a declaration T D where D has the form

  • type-qualifier-listopt D1

and the type of the identifier in the declaration T D1 is
type-modifier T,'' the type of the identifier of D istype-modifier type-qualifier-list pointer to T.’’ Qualifiers
following * apply to pointer itself, rather than to the object to
which the pointer points.

1
const char **s;

对于以上的声明,以*号界定,开始读:
以最右边第一个 * 号开始,形式为:
const char ** | s
最右面第一个s前没有修饰符,可以改变指针指向;s是指向const char **的指针(const char *就是指针),因此s也就是指向指针的指针;
再看第二个* 号,形式为:
为const char * | *s
由于*s前没有修饰符,因此(*s)其值是可以改变的;

最后看const char *,类似于前面的const int *p1,因此表示该指针(***s)指向的(此处为字符串)为常量,其值不可改变;

测试:

1
2
3
4
5
6
const char *fmt = "hello";
const char **s = &fmt;
*s++; //正确,指向改变了
(*s)++; //正确,指向的地址上的值,可以改变值
(**s)++; //报错,指向的地址上的值不可改变
**s++;

CATALOG
  1. 1. 指针
  2. 2. 简单示例
  3. 3. 就近原则