之前的文章有说过,使用指针我们可以改变指针指向的内容(通过给指针赋一个新的地址)或者改变被保存地址的值(通过给解引用指针赋一个新值):
int main()
{
int x { 5 }; // 创建一个整数变量 x,初始值为 5
int* ptr { &x }; // 创建一个指针 ptr,指向 x 的地址(非 const 指针)
int y { 6 }; // 创建一个整数变量 y,初始值为 6
ptr = &y; // 将 ptr 指向 y 的地址,我们可以改变它指向的地址
*ptr = 7; // 通过指针修改 ptr 所指向地址的值,即将 y 的值改为 7
return 0; // 程序成功结束
}
那么,如果我们想指向的值是const
呢?
int main()
{
const int x { 5 }; // x 现在是常量,值为 5
int* ptr { &x }; // 编译错误:不能将 const int* 转换为 int*,因为 x 是常量,不能修改它的值
return 0; // 程序正常结束
}
这段代码会出现编译错误,因为我们尝试将一个指向 const int
类型的指针赋值给一个普通的 int*
指针,C++
中不允许这样做。具体原因是 const
修饰符确保该变量的值在程序运行期间不能被修改,而普通的 int*
指针允许修改所指向的内容,所以会发生类型不匹配。
指向常量值的指针
指向常量值的指针(有时简称为指向 const 的指针)是一个(非 const)指针,它指向一个常量值。声明指向常量值的指针时,只需要在指针的数据类型之前使用const
关键字。
int main()
{
const int x {5};
const int* ptr = {&x};
*ptr = 6; // 非法操作:不能更改const值
return 0;
}
在上面的示例中, ptr
指向一个 const int
。因为被指向的数据类型是 const,所以指向的值不能被更改。
然而,因此指向常量的指针本身不是常量(而是它的指向是一个常量),所以,我们可以通过给指针赋值=一个新的地址来改变指针指向的内容。
int main()
{
const int x {5};
const int* ptr = {&x}; // ptr指向一个值为const的int类型的变量地址
const int y {6};
ptr = &y; // 指向一个新的地址
std::cout << ptr << '\n';
std::cout << *ptr << '\n';
return 0;
}
就像 const
引用一样,指向 const
的指针也可以指向非 const
变量。指向 const 的指针将所指向的值视为常量,不管该地址上的对象最初是否被定义为 const
。
有点绕口,看个例子助消化:
int main()
{
int x{ 5 }; // 非 const 变量,x 的初始值为 5
const int* ptr { &x }; // ptr 是一个指向 const int 的指针,指向 x
*ptr = 6; // 不允许:因为 ptr 指向的是 "const int",所以不能通过 ptr 修改值
x = 6; // 允许:因为 x 是非 const 的,直接修改 x 的值是可以的
return 0; // 程序结束
}
- **int x{ 5 };**这里定义了一个非
const
变量 x,并将其初始化为 5。 - const int* ptr { &x };:定义了一个指向
const int
类型的指针ptr
,它指向变量 x 的地址。虽然 x 是一个非const
变量,但指针ptr
被声明为指向const
类型的对象。这样,ptr
不能修改所指向的值。 - ***ptr = 6;**这是一个编译错误。虽然 x 是非
const
的,但由于ptr
是指向const int
的指针,编译器禁止通过该指针修改 x 的值。这是因为ptr
被声明为指向常量,所以它会将 x 视为常量 - **x = 6;**这行代码是允许的,因为
x
是非const
的,直接通过变量名 x 修改其值没有问题。指针的const
属性只影响通过指针访问数据时的行为,而不是通过普通的变量名。
常量指针
基于上述这些理论不难想到,我们也可以使指针本身成为常量。这就是常量指针,该指针是指其地址初始化后不能再次被更改。和普通的常量定义的概念是一致的,不过是将这个概念用在了指针类型上。
声明一个常量指针,在指针声明中的星号后面使用const
关键字即可:
int main()
{
int x{ 5 };
int* const ptr { &x }; //星号之后的const意味着这是const指针
return 0;
}
在上述情况下,
ptr
是一个指向(非 const)int 值的 const 指针。就像一个普通的 const 变量一样,const 指针必须在定义时初始化,并且这个值不能通过赋值来改变:
int main()
{
int x{ 5 }; // 创建一个整数变量 x,初始值为 5
int y{ 6 }; // 创建一个整数变量 y,初始值为 6
int* const ptr { &x }; // const 指针 ptr 被初始化为指向 x 的地址
ptr = &y; // 错误:一旦初始化,const 指针就不能改变它指向的地址
return 0; // 程序正常结束
}
然而,因为所指向的值是非 const 的,可以通过解引用 const 指针来更改所指向的值:
int main()
{
int x{ 5 };
int* const ptr { &x };
*ptr = 6;
return 0;
}
最后,可以通过在类型和星号之前和之后都是用const
关键字来声明一个指常量值的常量指针:
int main()
{
int value { 5 };
const int* const ptr { &value }; // 指常量值的常量指针
return 0;
}
一个指向常量值的常量指针不能改变其地址,也不能通过该指针改变它所指向的值。它只能解引用以获取它所指向的值。
小结一下
- 一个非
const
指针(例如int* ptr
)可以被分配另一个地址以改变它所指向的内容。 - 一个常量指针(例如
int* const ptr
)始终指向同一个地址,并且这个地址不能更改。 - 一个指向非
const
值的指针(例如int* ptr
)可以改变它所指向的值。这些指针不能指向const
值。 - 一个指向常量值的指针(例如
const int* ptr
)在通过该指针访问时将值视为常量,因此不能更改它所指向的值。这些指针可以指向常量或非常量左值(但不能指向右值,因为右值没有地址)。
感谢阅读、欢迎指正!