C++初学者指南-3.自定义类型(第一部分)-指针

C++初学者指南-3.自定义类型(第一部分)-指针

文章目录

  • C++初学者指南-3.自定义类型(第一部分)-指针
    • 1.为什么我们需要它们?
    • 2.T 类型的对象指针
      • 原始指针:T *
      • 智能指针(C++11)
    • 3.操作符
      • 地址操作符 &
      • 解引用运算符 *
      • 成员访问操作符 ->
      • 语法
      • 重定向
    • 4.nullptr (C++11)
    • 5.const 和指针
    • 6. "this"指针
    • 7.前置类型声明
    • 8. 尽量避免使用指针

1.为什么我们需要它们?

观察对象

  • 不复制的间接引用:引用/跟踪对象
  • 如果我们想要在运行时更改间接目标 ⇒ 不能使用引用

访问动态内存

  • 访问具有动态存储期的对象,即生命周期不与变量或作用域绑定的对象(后续章节会介绍)。

构建动态的、基于节点的数据结构
在这里插入图片描述

2.T 类型的对象指针

  • 存储 T 类型对象的内存地址
  • 可用于检查/观察/修改目标对象
  • 可以重定向到不同的目标(与引用不同)
  • 也可能指向根本没有的对象(是 Null 指针)
    在这里插入图片描述

原始指针:T *

  • 本质上是一个(无符号的)整数变量,用于存储内存地址
  • 大小:64 位平台上为64 位
  • 许多原始指针可以指向相同的地址/对象
  • 指针和目标(被指向的)对象的生命周期是独立的

智能指针(C++11)

std::unique_pointer

  • 用于访问动态存储,即堆上的对象
  • 每个对象只能有一个 unique_ptr
  • 指针和目标对象具有相同的生命周期

std::shared_pointer
std::weak_pointer

  • 用于访问动态存储,即堆上的对象
  • 每个对象可以有多个shared_ptrs 或 weak_ptrs
  • 只要至少有一个shared_ptr指向目标对象,目标对象就会存在

我们将在后面的章节中学习如何使用这些智能指针。

3.操作符

地址操作符 &

char  c = 65;
char* p = &c;
  • T* 类型的原始指针变量可以存储 T 类型对象的地址。
  • &c 返回 C 的内存地址
    在这里插入图片描述

解引用运算符 *

char  c = 65;
char* p = &c;
*p = 88;
char  x = *p;
  • &c 返回 c 的内存地址
  • *p 访问 p 中地址的值
    在这里插入图片描述

成员访问操作符 ->

struct Coord {char x = 0; char y = 0; 
};
Coord a {12,34};
Coord* p = &a;
char v = p->x;  // v = 12
char w = p->y;  // w = 34
// 另外的方式:
char s = (*p).x;  // s = 12
char t = (*p).y;  // t = 34

在这里插入图片描述

语法

*&
类型修饰符指针声明引用声明
一元运算符解引用
value = *pointer;
取得地址
pointer = &variable;
二元运算符乘法
product = expr1 * expr2;
按位与
bitand = expr1 & expr2;

声明陷阱

int*  p1, p2;    // int*, int
int  *p1, *p2;   // int*, int*

更好且更明确:

int* p1 = …;
int* p2 = …;

重定向

与引用不同,指针可以重定向

int a = 0;
int b = 0;            // a: 0    b: 0 
int* p = &a;          // p→a   a: 0    b: 0
*p = 2;               // p→a   a: 2    b: 0
p = &b;               // p→b   a: 2    b: 0
*p = 9;               // p→b   a: 2    b: 9
cout << a;  // 2
cout << b;  // 9

运行上面代码

4.nullptr (C++11)

  • 特殊指针值
  • 可以隐式转换为 false
  • 在内存中不一定用 0 表示! (取决于平台)

编码约定:nullptr 表示值不可用

  • 在初始化时将指针设置为 nullptr 或有效地址
  • 在解引用之前检查是否不是 nullptr
int* p = nullptr;   // 初始化为nullptr
if (…) {                             int i = 5;p = &i;  // 分配有效地址…// 在解引用之前检查!if (p) *p = 7;  …// 设置为nullptr,表示“不可用”。p = nullptr;   
}                             
// i的内存被释放,任何指向i的指针都会变得无效!

5.const 和指针

目的

  1. 只读访问对象
  2. 防止指针重定向

语法

指向类型 T 的指针指向值可修改指针本身可修改
T *可以可以
T const *不可以可以
T * const可以不可以
T const * const不可以不可以

从右到左读:“(const)指向(const)T的指针”
例子:

int i = 5;
int j = 8;
int const* cp = &i;
*cp = 8;   //  编译器错误:指向的值是const
cp = &j;   //  OK
int *const pc = &i;
*pc = 8;   //  OK
pc = &j;   //  编译器错误:指针本身是常量
int const*const cpc = &i;
*cpc = 8;  //  编译器错误:指向的值是常量
cpc = &j;  //  编译器错误:指针本身是常量

一个关于风格的持续辩论…

右const左const
一个一贯的规则: const 的剩余部分保持不变更普遍,但不太一致
int const c = …;
int const& cr = …;
int const* pc = …;
int *const cp = …;
int const * const cpc = …;
const int c = 1;
const int& cr = …;
const int* pc = …;
int *const cp = …;
const int *const cpc = …;

6. "this"指针

  • 成员函数内部可用
  • this 返回对象本身的地址
  • this-> 可用于访问成员
  • *this 访问对象本身
class IntRange {int l_ = 0;int r_ = 0;
public:explicitIntRange (int l, int r): l_{l}, r_{r} {if (l_ > r_) std::swap(l_, r_);}int left ()  const { return l_; }// can also use 'this' to access members:int right () const { return this->r_; }// returns reference to object itselfIntRange& shift (int by) {l_ += by;r_ += by;return *this;}IntRange& widen (int by) {l_ -= by;r_ += by;return *this;}
};

运行上面代码

IntRange r1 {1,3};                  // 1 3
r1.shift(1);                        // 2 4
r1.shift(2).widen(1);               // 3 7

7.前置类型声明

有时候如果需要让两种类型相互引用的话是必要的:

// 前置声明
class Hub;
class Device {Hub* hub_;…
};
class Hub {std::vector<Device const*> devs_;…
};

在这里插入图片描述
为了定义一个类型,必须要知道它所有成员的内存大小。

  • 这只有在完全了解所有成员的定义的情况下才可能实现。
  • 但是,所有指针类型都具有相同的大小

⇒我们可以:
声明 Hub 的存在,因为 Device 只需要一个指向它的指针。

8. 尽量避免使用指针

指针容易悬空

  • 悬空 = 指向无效/无法访问的内存地址的指针
  • 存储在指针中的值可以是任何地址
  • 程序员必须确保指针目标有效/仍然存在
int* p;  // p 没有初始化!
*p = 7;  //  未知行为
p = nullptr;  
*p = 7;  //  访问空指针导致未知行为
{int x = 8;  p = &x;   
}        // x的生命周期已经结束
*p = 7;  // 访问已经释放的内存导致未知行为

容易出错的参数传递

void swap_values (int* a, int* b) {int t = *a;*a = *b;*b = t;
}
int x = 3, y = 4;
swap_values(&x, &y)        // OK
swap_values(&x, 0);        //  未知行为
swap_values(&x, nullptr);  //  未知行为

代码更难阅读

*p = *p * *p + (2 * *p + 1);   // 太多星号了!

建议:如果可能,首选引用,尤其是对于函数参数

附上原文地址
如果文章对您有用,请随手点个赞,谢谢!^_^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/37693.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SCADA系统对于工业生产的意义!

关键字:LP-SCADA系统, 传感器可视化, 设备可视化, 独立SPC系统, 智能仪表系统,SPC可视化,独立SPC系统 SCADA系统在智能制造中扮演着至关重要的角色&#xff0c;它通过集成和自动化工厂车间的各种过程&#xff0c;提高了生产效率和产品质量&#xff0c;降低了成本&#xff0c;并…

【AI绘画 ComfyUI】全新整合包来袭!一键安装 即开即用,超好用的工作流形式的AI绘画工具!

大家好&#xff0c;我是画画的小强 请在看这篇文章的人注意&#xff0c;本文章介绍的Comfy UI整合包是一个节点式的工作&#xff0c;流式的AI绘画界面&#xff0c;并不适合新手使用。 如果你在找的是Web UI, 请前往我之前发布一篇的文章AI绘画『Stable Diffusion』面向小白的…

【高中数学/基本不等式】设a,b>0.a+b=5,则 根号下(a+1)+根号下(b+3) 的最大值为?(2015重庆卷)

【问题】 设a,b>0.ab5,则根号下(a1)根号下(b3)的最大值为&#xff1f; 【解答】 解法一&#xff1a; 因双根号计算不便&#xff0c;故采用平方后简化之。 原式的平方a12倍根号下((a1)(b3))b3 ab42倍根号下((a1)(b3)) 因为ab5 a1b31359 9(a1)(b3)>2倍根号下((a1)…

【小贪】项目实战——Zero-shot根据文字提示分割出图片目标掩码

目标描述 给定RGB视频或图片&#xff0c;目标是分割出图像中的指定目标掩码。我们需要复现两个Zero-shot的开源项目&#xff0c;分别为IDEA研究院的GroundingDINO和Facebook的SAM。首先使用目标检测方法GroundingDINO&#xff0c;输入想检测目标的文字提示&#xff0c;可以获得…

uniapp中如何进行微信小程序的分包

思路&#xff1a;在uniapp中对微信小程序进行分包&#xff0c;和原生微信小程序进行分包的操作基本上没区别&#xff0c;主要就是在pages.json中进行配置。 如图&#xff0c;我新增了一个包diver-page 此时需要在pages.json中的subPackages数组中新增一项 root代表这个包的根…

用好华为小助手,生活总能快人一步

嘿&#xff01;朋友们&#xff01;你们有没有想过&#xff0c;如果身边有一个小助手&#xff0c;他不仅聪明伶俐&#xff0c;还能在生活的方方面面给予你最贴心的关怀和帮助&#xff0c;让我们的日常生活变得更加方便和快捷&#xff0c;那该有多好&#xff01;没错&#xff0c;…

谈谈创意设计中的AI、AGI、AIGC

在当今的数字化时代&#xff0c;创意设计领域正经历着前所未有的变革。随着人工智能&#xff08;AI&#xff09;、通用人工智能&#xff08;AGI&#xff09;以及人工智能生成内容&#xff08;AIGC&#xff09;的迅猛发展&#xff0c;设计师们的工作方式和创作手段都发生了深刻的…

Swift 中的 StoreKit 测试

文章目录 前言创建一个 StoreKit Demo使用 SKTestSessionaskToBuyEnabled 属性总结前言 StoreKit 框架的第二次迭代是我在过去几年中应用程序中最重大的变化。最近版本的 StoreKit 框架已完全采用了 Swift 语言特性,如 async 和 await。本篇内容我们将讨论 StoreKitTest 框架…

【揭秘】嘴尚绝卤味健康新风尚,让你吃得美味又健康!

在快节奏的现代生活中&#xff0c;美食不仅是味蕾的享受&#xff0c;更是健康生活的追求。今天&#xff0c;我们要聊的就是备受食客们青睐的“嘴尚绝卤味”——如何在享受美味的同时&#xff0c;也能兼顾健康饮食的理念。 一、卤味文化&#xff0c;源远流长 卤味&#xff0c;作…

Redis缓存管理机制

在当今快节奏的数字世界中&#xff0c;性能优化对于提供无缝的用户体验至关重要。缓存在提高应用程序性能方面发挥着至关重要的作用&#xff0c;它通过将经常使用或处理的数据存储在临时高速存储中来减少数据库负载并缩短响应时间&#xff0c;从而减少系统的延迟。Redis 是一种…

navicat Lite 版

navicat Lite 版&#xff1a; Navicat 出了一个 Navicat Premium 的Lite版。 官方现在链接&#xff1a;https://www.navicat.com.cn/download/navicat-premium-lite#windows 从官网可以看到现在能够下载最新版本 17&#xff0c;支持各种平台

[vue2/vue3] 详细剖析watch、computed、watchEffect的区别,原理解读

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是前端菜鸟的自我修养&#xff01;今天给大家分享【深入剖析watch、computed、watchEffect的区别】&#xff0c;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;原创不易&#xff0c;如果能帮助到带大家…

为什么企业应用开发,c++干不过java?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; C/C这种东西&#xff0c;根本…

一个 API 客户端和一份 TS 学习手册

第75期&#xff1a; Insomnia&#xff1a;超好看的 API 客户端 项目介绍&#xff1a; 一款适用于 GraphQL、REST、WebSockets 和 gRPC 的开源 API 客户端&#xff0c;颜值超高。 跨平台&#xff0c;支持 Mac、Windows 和 Linux。但不支持网页版&#xff0c;需要下载客户端。…

Supabase 自托管部署实践

Supabase 是 Firebase 的开源替代品。使用 Postgres 数据库、身份验证、即时 API、边缘函数、实时订阅、存储和向量嵌入来启动您的项目。 Supabase介绍 Supabase 是一个开源的后端即服务&#xff08;BaaS&#xff09;平台&#xff0c;提供了一系列工具和服务&#xff0c;帮助…

CrimsonEDR:一款恶意软件模式识别与EDR策略评估工具

关于CrimsonEDR CrimsonEDR是一个功能强大的开源项目&#xff0c;该项目旨在帮助广大研究人员识别特定的恶意软件模式&#xff0c;以此来优化终端检测与响应&#xff08;EDR&#xff09;的策略方案。通过使用各种不同的检测方案&#xff0c;可以加深开发人员与研究人员加深对安…

SpringBoot入门实战:SpringBoot整合WebSocket

1.背景介绍 SpringBoot是一个快速开发的框架&#xff0c;它可以帮助我们快速开发Web应用程序。SpringBoot整合WebSocket是SpringBoot的一个组件&#xff0c;它可以帮助我们快速开发WebSocket应用程序。 WebSocket是一种新的协议&#xff0c;它可以让客户端和服务器之间建立持久…

MSYS2教程(windows环境下使用linux工具)

MSYS2教程(windows环境下使用linux工具) 1.msys2简介 MSYS2&#xff08;Minimal SYStem 2&#xff09;是一个集成了大量的GNU工具链、工具和库的开源软件包集合。它提供了一个类似于Linux的shell环境&#xff0c;可以在Windows系统中编译和运行许多Linux应用程序和工具。 MS…

excel修改批量一列单价的金额并保留1位小数

1.打开表格&#xff0c;要把单价金额变成现在的两倍&#xff0c;数据如下&#xff1a; 2.把单价这一列粘贴到一个新的sheet页面&#xff0c;在B2单元格输入公式&#xff1a;A2*2 然后按enter回车键,这时候吧鼠标放到B2单元格右下角&#xff0c;会出现一个黑色的小加号&#xf…

《信创数据库沙龙上海站:共话发展,智启未来》

2024 年 6 月 29 日周六 14:00&#xff0c;信创数据库沙龙在上海市徐汇区建国西路 285 号科投大厦 13 楼金星厅成功举办。本次活动吸引了众多学术界和产业界的专家、学者以及技术爱好者参与。 活动中&#xff0c;多位嘉宾带来了精彩分享。薛晓刚探讨了 Oracle 在国内的前景&a…