const在星号左边修饰指针的指向,在星号右边修饰指针自身
int main()
{
int a = 10, b = 20;
int* p1 = &a;// *是修饰符
*p1 = 100; //*是解引用
const int* p2 = &a;
//*p2 = 100; //error,const修饰了指针的指向,不能通过指针修改
//p2 = &b; //ok
int const * p3 = &a;
int * const p4 = &a;
*p4 = 100;//ok
p4 = &b;//error,const修饰的是指针自身,不能修改
const int* const p5 = &a;
*p5 = 100;//error
p5 = &b;//error
}
下面,做几个例题分析一下:
第一个:
int main()
{
const int a = 10;
int b = 20;
int *p1 = &a;
const int *p2 = &a;
int* const p3 = &a;
const int* const p4= &a;
}
代码分析:在此代码中,a为常性,即a自身的值不能被改变,p1保存a的地址,因为a是常性,所以在定义指针时,应该不能通过指针修改a的值,所以应该在*的左边加上const,表示该指针不能修改指向,因此上述代码只有p2和p4能够编译通过。
第二个:
int main()
{
int a = 10, b = 20;
const int* p = &a;
int* s1 = p;
const int *s2 = p;
int* const s3 = p;
const int* const s4= p;
}
代码分析:在此代码中,p的指向被修饰为常性,意味着不能通过指针修改a的值,因此,如果再定义一个指针保存p的地址时,新指针不能通过解引用进行修改,即在传递的过程中不允许能力扩张,上述代码中s2和s4可以被编译通过。
第三个:
如下,如果将p自身修饰为常性,哪些不能编译通过:
int main()
{
int a = 10, b = 20;
int* const p = &a;
int* s1 = p;
const int *s2 = p;
int* const s3 = p;
const int* const s4= p;
}
首先,我们声明了一个常量指针 p 。这意味着 p 是一个指向 int的指针,并且 p本身是一个常量,即 p的值(即它所存储的地址)不能被改变,但是通过 p所指向的 int值是可以被改变的。
接下来,我们逐一分析其他指针的声明:
int* s1 = p;
这里尝试将一个 int* const(即 p)赋值给一个 int*。由于 p`指向的 int 值可以修改(尽管 p 本身不能改变指向),这个赋值是合法的。
const int *s2 = p;
这里将 p 赋值给一个 const int*。这意味着 s2`是一个指向常量的指针,通过 s2 不能修改所指向的 int值,但 s2可以指向不同的地址(尽管在这个例子中它不会这样做)。这个赋值也是合法的,因为 p 并不承诺通过它修改值是不允许的,只是 p 自己不能改变指向。
int* const s3 = p;
这里尝试将 p 赋值给一个 int* const。这实际上与 p 的声明是相同的类型。因此,这个赋值是合法的,s3 将像 p 一样指向 a 的地址,并且 s3 本身也不能改变指向。
const int* const s4 = p;
这里尝试将 p 赋值给一个 const int* const。这意味着 s4 是一个指向常量的常量指针,即 s4 指向的地址不能改变,且通过 s4 指向的 int 值也不能被修改。这里的问题是,虽然 p 指向的 int 值可以通过p修改(因为 `p` 不是 const int*),但 s4 作为一个 const int* 类型的指针,要求它指向的值不能被修改。这种赋值在技术上是不允许的,因为 p 允许修改它所指向的值,而 s4 不允许。然而,在C++的实践中,由于 p 并不承诺不修改指向的值(它只是自己不能改变指向),并且 s4 只是承诺不会修改这个值,这种赋值通常是被编译器接受的,因为它不会违反 s4 的任何约束(s4 只是承诺不修改值,并不关心 p 是否允许修改值)。但理论上,这种赋值可能引起理解上的混淆,因为它依赖于未明确表达的行为(即 p 实际上是否会修改值)。不过,在大多数编译器中,这个赋值是可以通过编译的。