12-9 指针和常量
请看以下代码片段:
int main()
{
int x { 5 };
int* ptr { &x }; // ptr is a normal (non-const) pointer
int y { 6 };
ptr = &y; // we can point at another value
*ptr = 7; // we can change the value at the address being held
return 0;
}
对于普通(非常量)指针,我们可以改变指针指向的内容(通过给指针分配一个新的地址),也可以改变指针所指向的地址处的值(通过给解引用的指针分配一个新值)。
但是,如果我们要指向的值是常量(const)会发生什么情况呢?
int main()
{
const int x { 5 }; // x is now const
int* ptr { &x }; // compile error: cannot convert from const int* to int*
return 0;
}

上面的代码片段无法编译——我们不能将一个非常量指针指向一个常量变量。这很合理:常量变量的值不能被改变。如果允许程序员将一个非常量指针指向一个常量值,那么程序员就可以解引用该指针并改变其值。这将违反变量的常量性。
指向常量值的指针
指向常量值的指针(有时简称 pointer to const)是指向常量值的(非常量)指针。
要声明指向常量值的指针,请
在指针的数据类型前使用关键字const:
int main()
{
const int x{ 5 };
const int* ptr { &x }; // okay: ptr is pointing to a "const int"
*ptr = 6; // not allowed: we can't change a const value
return 0;
}

在上面的例子中,ptr指向一个常量const int。因为被指向的数据类型是常量,所以被指向的值不能更改。
然而,由于指向常量的指针本身并不是常量(它只是指向一个常量值),我们可以通过给指针分配一个新地址来改变指针指向的内容:
int main()
{
const int x{ 5 };
const int* ptr { &x }; // ptr points to const int x
const int y{ 6 };
ptr = &y; // okay: ptr now points at const int y
return 0;
}
与引用 const 类似,指向 const 的指针也可以指向非常量变量。指向 const 的指针会将指向的值视为常量,无论该地址处的对象最初是否被定义为 const:
int main()
{
int x{ 5 }; // non-const
const int* ptr { &x }; // ptr points to a "const int"
*ptr = 6; // not allowed: ptr points to a "const int" so we can't change the value through ptr
x = 6; // allowed: the value is still non-const when accessed through non-const identifier x
return 0;
}

常量指针
我们还可以将指针本身设为常量。常量指针是指初始化后地址不能改变的指针。
要声明一个常量指针,请在指针声明中星号后面使用关键字 const:
int main()
{
int x{ 5 };
int* const ptr { &x }; // const after the asterisk means this is a const pointer
return 0;
}
在上述例子中,ptr是一个指向(非常量)整数值的常量指针。
与普通的常量变量一样,常量指针必须在定义时进行初始化,并且不能通过赋值来改变其值:
int main()
{
int x{ 5 };
int y{ 6 };
int* const ptr { &x }; // okay: the const pointer is initialized to the address of x
ptr = &y; // error: once initialized, a const pointer can not be changed.
return 0;
}

但是,由于被指向的值非常量,因此可以通过解引用 const 指针来改变被指向的值:
int main()
{
int x{ 5 };
int* const ptr { &x }; // ptr will always point to x
*ptr = 6; // okay: the value being pointed to is non-const
return 0;
}
指向常量值的常量指针
最后,可以通过在类型之前和星号之后使用关键字const来声明向常量值的常量指针:
int main()
{
int value { 5 };
const int* const ptr { &value }; // a const pointer to a const value
return 0;
}
指向常量值的常量指针的地址不能被改变,它所指向的值也不能通过该指针被改变。它只能被解引用来获取它所指向的值。
补充:
指针和常量概述
总而言之,你只需要记住4条规则,而且它们非常符合逻辑:
- 非常量指针(例如
int* ptr)可以被赋予另一个地址,以改变它所指向的内容。 - 常量指针(例如
int* const ptr)始终指向同一个地址,并且该地址不能更改。 - 指向非常量值的指针(例如
int* ptr)可以改变它所指向的值。指向非常量值的指针不能指向常量值。 - 指向常量值的指针(例如
const int* ptr)在通过该指针访问该值时,会将该值视为常量,因此不能更改它所指向的值。这些指针可以指向常量或非常量左值(但不能指向右值,因为右值没有地址)。
保持声明语法的正确性可能有点挑战性:
const星号前的A (例如 const int* ptr)与所指向的类型相关联。因此,这是一个指向常量值的指针,并且该值不能通过指针进行修改。
const星号后的A (例如 int* const ptr)与指针本身关联。因此,该指针不能被赋予新的地址。
int main()
{
int v{ 5 };
int* ptr0 { &v }; // points to an "int" but is not const itself. We can modify the value or the address.
const int* ptr1 { &v }; // points to a "const int" but is not const itself. We can only modify the address.
int* const ptr2 { &v }; // points to an "int" and is const itself. We can only modify the value.
const int* const ptr3 { &v }; // points to a "const int" and is const itself. We can't modify the value nor the address.
// if the const is on the left side of the *, the const belongs to the value
// if the const is on the right side of the *, the const belongs to the pointer
return 0;
}


浙公网安备 33010602011771号