C++之const指针和const变量
C++中的int * const a
是指的该变量的指针地址是不能变化的,但是对应的指针地址内存的值是可以变的。
const int * a
是指的该变量是常量,指针指向的值是不能改变,但是值是不能改变的
如何记忆
记住这两种指针声明方式的关键在于理解 const
的作用范围。下面提供两种实用的记忆方法:
1. “靠近谁,保护谁” 规则
const
修饰靠近的对象,保护它不被修改。- 如果
const
靠近的是int
,就表示指针所指向的值不能修改。 - 如果
const
靠近的是指针*
,就表示指针本身不能修改(即指针地址不能变)。
- 如果
例子:
const int * a
:const
靠近int
,说明int
是常量,指向的值不能变,但指针a
本身可以变。int * const a
:const
靠近*
,说明指针a
是常量,指针地址不能变,但指向的值可以修改。
2. “从右往左读” 规则
这是另一种简单的记忆方法,通过从右往左的方式来读声明,从而理解它的含义。
例子:
const int * a
:从a
开始读,a
是一个指向const int
的指针,所以指向的值不能修改,但a
本身可以指向别的地址。int * const a
:从a
开始读,a
是一个const
指针,指向int
,所以指针地址不能修改,但所指向的值可以修改。
总结:
- 靠近谁,保护谁:
const
靠近int
时保护值,靠近*
时保护指针地址。 - 从右往左读:读清楚声明的顺序,以理解是保护值还是保护指针。
这两种方法都可以帮助你迅速区分指针的类型和行为,找到自己喜欢的方式记忆即可。
实际应用
const int * a
表示指针可以改变它指向的地址,但指针所指向的值是不可变的。这意味着你可以让指针指向不同的对象或变量,但不能通过这个指针修改它指向的内容。
一个实际的应用场景是函数参数中的只读访问。假设我们有一个函数需要访问传入的数组元素,但是我们不希望函数修改这些元素。这时我们可以用 const int *
来保证数据的安全性。
应用场景:读取数据但不修改
假设有一个函数需要遍历一个整型数组,并计算其中所有元素的和,但为了保证数据的安全性,不允许修改数组的元素。可以使用 const int *
来实现这一目的:
#include <iostream>
int sum(const int *arr, int size) {
int total = 0;
for (int i = 0; i < size; ++i) {
total += arr[i]; // 可以读取数组元素的值
// arr[i] = 10; // 错误,不能通过 const int * 修改数组的值
}
return total;
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
const int *ptr = numbers; // 指针指向数组,但不能修改数组中的值
std::cout << "Sum of numbers: " << sum(ptr, 5) << std::endl;
// 可以让指针指向其他内存位置
int other_numbers[] = {10, 20, 30};
ptr = other_numbers; // ptr 指向新的数组
std::cout << "Sum of other numbers: " << sum(ptr, 3) << std::endl;
return 0;
}
代码分析:
-
const int *arr
:这个函数参数声明意味着arr
是一个指向常量整数的指针。通过arr
可以读取数组的元素,但不能修改它们。 -
在
main()
中:const int *ptr = numbers;
:ptr
指向了数组numbers
的首元素,但因为它是const int *
类型的指针,不能修改数组元素。ptr = other_numbers;
:指针ptr
可以指向另一个数组other_numbers
,但同样,它只能读取该数组的值,不能修改它。
输出:
Sum of numbers: 15
Sum of other numbers: 60
总结:
- 在函数中使用
const int *
来限制对传入数据的修改,确保函数只能读取而不能修改数据。 - 指针可以指向不同的内存地址(数组或其他变量),但通过这个指针不能修改指向的值。
这种应用场景常用于需要保护传入数据不被修改的函数、类成员函数或接口设计中,确保数据安全和防止意外修改。
int * const a
表示指向整数的常量指针,即指针本身是常量,不能改变指向的地址,但可以通过指针修改指向的值。这个指针指向的地址一旦被初始化,就不能再指向其他地址。
应用场景:指针本身不变,但可以修改内容
当你希望指针一直指向同一个变量或内存地址,并且只修改该内存中的值时,可以使用 int * const
来保证指针的地址不变。典型的应用场景是当指针用于管理资源或者关键数据时,保证指针不会被意外地重新指向其他位置,但你可以通过指针来修改它所指向的数据。
例子:管理数据缓冲区
假设有一个程序管理一个固定的数据缓冲区。你希望缓冲区的指针始终指向固定的内存位置,但允许修改缓冲区内的数据。这时,可以用 int * const
来保证指针指向固定的缓冲区。
#include <iostream>
void modifyBuffer(int * const buffer, int size) {
for (int i = 0; i < size; ++i) {
buffer[i] = i * 10; // 可以通过指针修改缓冲区的值
}
// buffer = nullptr; // 错误,不能修改 buffer 的地址
}
int main() {
int buffer[5] = {0, 0, 0, 0, 0}; // 一个固定大小的缓冲区
int * const bufferPtr = buffer; // bufferPtr 是指向缓冲区的常量指针
modifyBuffer(bufferPtr, 5); // 通过常量指针修改缓冲区内容
// 打印缓冲区中的值
for (int i = 0; i < 5; ++i) {
std::cout << buffer[i] << " "; // 输出:0 10 20 30 40
}
std::cout << std::endl;
// 尝试修改指针地址会报错
// bufferPtr = new int[5]; // 错误,不能修改常量指针的地址
return 0;
}
代码分析:
-
int * const bufferPtr
:声明一个常量指针bufferPtr
,它指向buffer
数组。由于bufferPtr
是常量指针,不能修改它指向的地址,即bufferPtr
始终指向buffer
。 -
在
modifyBuffer()
函数中:- 通过
buffer[i] = i * 10;
修改了缓冲区中的数据。由于buffer
是指向数组的常量指针,所以可以修改它指向的值。 - 不能修改指针地址,如
buffer = nullptr;
是非法的,因为buffer
是常量指针。
- 通过
输出:
0 10 20 30 40
总结:
int * const a
表示指针地址不能改变,即指针在初始化后必须一直指向相同的地址,但通过该指针可以修改所指向的值。- 这种用法非常适合那些需要指针保持指向固定位置(如固定缓冲区、资源句柄等),但允许修改该位置的数据的情况。
这个例子展示了一个常量指针如何保持对缓冲区的固定引用,同时通过该指针可以安全地修改缓冲区的数据,而不会意外更改指针指向的地址。