[通俗易懂C++]:指针和const

news/2025/2/24 5:17:06

之前的文章有说过,使用指针我们可以改变指针指向的内容(通过给指针赋一个新的地址)或者改变被保存地址的值(通过给解引用指针赋一个新值):

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,所以指向的值不能被更改。

然而,因此指向常量的指针本身不是常量(而是它的指向是一个常量),所以,我们可以通过给指针赋值=一个新的地址来改变指针指向的内容。

image-20250222224723856

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 )在通过该指针访问时将值视为常量,因此不能更改它所指向的值。这些指针可以指向常量或非常量左值(但不能指向右值,因为右值没有地址)。

感谢阅读、欢迎指正!


http://www.niftyadmin.cn/n/5863974.html

相关文章

如何手动设置u-boot的以太网的IP地址、子网掩码、网关信息、TFTP的服务器地址,并进行测试

设置IP地址 运行下面这条命令设置u-boot的以太网的IP地址&#xff1a; setenv ipaddr 192.168.5.9设置子网掩码 运行下面这条命令设置u-boot的以太网的子网掩码&#xff1a; setenv netmask 255.255.255.0设置网关信息 运行下面这条命令设置u-boot的网关信息&#xff1a; …

案例-14.文件上传-简介

一.简介 文件上传涉及到两个部分&#xff0c;一个是前端程序&#xff0c;另一个是服务端程序。 二.前端程序 1.前端上传文件必须有三要素&#xff1a; 1.form表单&#xff0c;并且在form表单中要定义一个表单项&#xff0c;类型为file。其效果是会弹出一个“选择文件”的按钮…

深度学习pytorch之19种优化算法(optimizer)解析

提示&#xff1a;有谬误请指正 摘要 本博客详细介绍了多种常见的深度学习优化算法&#xff0c;包括经典的LBFGS 、Rprop 、Adagrad、RMSprop 、Adadelta 、ASGD 、Adamax、Adam、AdamW、NAdam、RAdam以及SparseAdam等&#xff0c;通过对这些算法的公式和参数说明进行详细解析…

解决Excel文件格式损坏问题:如何通过程序读取并复制内容

在日常工作中&#xff0c;我们经常会遇到因文件损坏或格式问题无法打开的 Excel 文件。尤其是 .xls 格式的旧版 Excel 文件&#xff0c;在某些情况下可能由于损坏、格式不兼容或其他原因&#xff0c;导致无法通过常规方式读取和处理。本文将分享一种通过 Python 程序解决损坏的…

C#上位机--进程和线程的区别

引言 在 C# 上位机开发中&#xff0c;进程和线程是两个非常重要的概念&#xff0c;它们在程序的运行和性能优化方面起着关键作用。理解进程和线程的区别&#xff0c;能够帮助开发者更好地设计和实现高效、稳定的上位机程序。本文将深入探讨 C# 上位机中进程和线程的区别&#…

结构型模式-Bridge模式(桥接模式)

解释 桥接模式是将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。它是一种对象结构型模式。 Bridge模式核心思想将抽象与实现解耦&#xff0c;使二者可以独立变化。适用于一个类存在多个变化维度且需要灵活扩展的场景。 场景假设&#xff1a;图形渲染系统 …

体育电竞比分网开发流程

开发一个体育电竞比分网的流程可以分为以下几个主要步骤&#xff1a; 1. 需求分析 目标用户&#xff1a;确定网站的主要用户群体&#xff0c;如体育迷、电竞爱好者等。 功能需求&#xff1a;列出网站需要实现的功能&#xff0c;如实时比分更新、赛事日程、新闻资讯、用户评论…

c++ std::vector使用笔记

std::vector 是 C 标准库中的一个动态数组容器&#xff0c;提供了丰富的接口来管理容量、插入、删除和访问元素。以下是对你提到的接口的详细说明和使用示例&#xff1a; 1. 容量相关接口 capacity(): 返回当前 vector 分配的存储空间大小&#xff08;以元素数量计&#xff09…