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;
}

image

上面的代码片段无法编译——我们不能将一个非常量指针指向一个常量变量。这很合理:常量变量的值不能被改变。如果允许程序员将一个非常量指针指向一个常量值,那么程序员就可以解引用该指针并改变其值。这将违反变量的常量性。

指向常量值的指针

指向常量值的指针(有时简称 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;
}

image

在上面的例子中,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;
}

image

常量指针

我们还可以将指针本身设为常量。常量指针是指初始化后地址不能改变的指针。

要声明一个常量指针,请在指针声明中星号后面使用关键字 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;
}

image

但是,由于被指向的值非常量,因此可以通过解引用 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;
}

指向常量值的常量指针的地址不能被改变,它所指向的值也不能通过该指针被改变。它只能被解引用来获取它所指向的值。

补充:
image

指针和常量概述

总而言之,你只需要记住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;
}
posted @ 2025-12-17 18:56  游翔  阅读(14)  评论(0)    收藏  举报