当前位置: 首页 > article >正文

C++之const指针和const变量

C++中的int * const a是指的该变量的指针地址是不能变化的,但是对应的指针地址内存的值是可以变的。
const int * a是指的该变量是常量,指针指向的值是不能改变,但是值是不能改变的

如何记忆

记住这两种指针声明方式的关键在于理解 const 的作用范围。下面提供两种实用的记忆方法:

1. “靠近谁,保护谁” 规则

  • const 修饰靠近的对象,保护它不被修改。
    • 如果 const 靠近的是 int,就表示指针所指向的值不能修改
    • 如果 const 靠近的是指针 *,就表示指针本身不能修改(即指针地址不能变)。
例子:
  • const int * aconst 靠近 int,说明 int 是常量,指向的值不能变,但指针 a 本身可以变。
  • int * const aconst 靠近 *,说明指针 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;
}

代码分析:

  1. const int *arr:这个函数参数声明意味着 arr 是一个指向常量整数的指针。通过 arr 可以读取数组的元素,但不能修改它们。

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

代码分析:

  1. int * const bufferPtr:声明一个常量指针 bufferPtr,它指向 buffer 数组。由于 bufferPtr 是常量指针,不能修改它指向的地址,即 bufferPtr 始终指向 buffer

  2. modifyBuffer() 函数中:

    • 通过 buffer[i] = i * 10; 修改了缓冲区中的数据。由于 buffer 是指向数组的常量指针,所以可以修改它指向的值。
    • 不能修改指针地址,如 buffer = nullptr; 是非法的,因为 buffer 是常量指针。

输出:

0 10 20 30 40

总结:

  • int * const a 表示指针地址不能改变,即指针在初始化后必须一直指向相同的地址,但通过该指针可以修改所指向的值。
  • 这种用法非常适合那些需要指针保持指向固定位置(如固定缓冲区、资源句柄等),但允许修改该位置的数据的情况。

这个例子展示了一个常量指针如何保持对缓冲区的固定引用,同时通过该指针可以安全地修改缓冲区的数据,而不会意外更改指针指向的地址。


http://www.kler.cn/news/356947.html

相关文章:

  • 【Python】基础语法-输入输出
  • Mongodb基础用法【总结】
  • ‘perl‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
  • JS异步编程进阶(二):rxjs与Vue、React、Angular框架集成及跨框架状态管理实现原理
  • 【React】事件绑定的方式
  • 【SSM详细教程】-03-Spring参数注入
  • 解锁A/B测试:如何用数据驱动的实验提升你的网站和应用
  • 过滤器Filter的介绍和使用
  • 聊聊 Facebook Audience Network 绑定收款账号的问题
  • Linux执行source /etc/profile命令报错:权限不够问(已解决)
  • Linux 之 fdisk 【磁盘分区管理】
  • oracle + mybatis 批量新增
  • lodash 和 lodash-es 的区别
  • leetcode289:生命游戏
  • Java基于微信小程序的公考学习平台的设计与实现,附源码+文档
  • 面试八股(自用)
  • Ubuntu22.04安装RTX3080
  • 汽车零部件行业CRM应用数字化解决方案解析
  • 【服务器部署】Docker部署小程序
  • 【Flutter】- go_router路由