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

news2024/11/23 20:44:32

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:
  explicit
  IntRange (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 itself
  IntRange& 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.coloradmin.cn/o/1883858.html

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

相关文章

QT5:在窗口右上角显示图标

目录 一、环境与目标 二、实现逻辑&#xff08;纯代码&#xff09;与效果 三、参考代码 四、总结 一、环境与目标 qt版本&#xff1a;5.12.7 windows 11 下的 Qt Designer &#xff08;已搭建&#xff09; 目标&#xff1a;使用嵌套布局的方式将两个按钮显示在窗口右上角…

首款内置电源的迷你主机,不到千元的办公神器 | 零刻EQ13评测报告

零刻首款内置电源的迷你主机&#xff0c;不到千元的办公神器 | 零刻EQ13评测报告 哈喽小伙伴们好&#xff0c;我是Stark-C~ 众所周知&#xff0c;零刻作为目前国产迷你主机第一品牌&#xff0c;旗下系列众多&#xff0c;产线丰富&#xff0c;比如说它有针对游戏玩家的性能主机…

各类排序方法 归并排序 扩展练习 逆序对数量

七月挑战一个月重刷完Y总算法基础题&#xff0c;并且每道题写详细题解 进度:(3/106) 归并排序的思想也是分而治之 归并优点&#xff1a;速度稳定,排序也稳定 排序也稳定&#xff08;数组中有两个一样的值&#xff0c;排序之后他们的前后顺序不发生变化&#xff0c;我们就说…

一句话介绍什么是AI智能体?

什么是AI智能体&#xff1f; 一句话说就是利用各种AI的功能的api组合&#xff0c;完成你想要的结果。 例如你希望完成一个关于主题为啤酒主题的小红书文案图片&#xff0c;那么它就可以完成 前面几个步骤类似automa的组件&#xff0c;最后生成一个结果。

手把手搞定报名亚马逊科技认证

引言 亚马逊云科技认证考试为我们这些技术从业者提供了提升专业技能的机会。无论选择线上还是线下考试&#xff0c;每种方式都有其独特的优势和挑战。选择合适的考试方式将帮助我们更好地展示自己的技术水平。以下是我对不同考试方式的优缺点介绍&#xff0c;以及各科目的考试…

tkinter显示图片

tkinter显示图片 效果代码解析打开和显示图像 代码 效果 代码解析 打开和显示图像 def open_image():file_path filedialog.askopenfilename(title"选择图片", filetypes(("PNG文件", "*.png"), ("JPEG文件", "*.jpg;*.jpeg&q…

哈希表(C++实现)

文章目录 写在前面1. 哈希概念2. 哈希冲突3. 哈希函数4.哈希冲突解决4.1 闭散列4.1.1 线性探测4.1.2 采用线性探测的方式解决哈希冲突实现哈希表4.1.3 二次探测 4.2 开散列4.2.2 采用链地址法的方式解决哈希冲突实现哈希表 写在前面 在我们之前实现的所有数据结构中(比如&…

CesiumJS【Basic】- #042 绘制纹理线(Primitive方式)

文章目录 绘制纹理线(Primitive方式)1 目标2 代码2.1 main.ts3 资源文件绘制纹理线(Primitive方式) 1 目标 使用Primitive方式绘制纹理线 2 代码 2.1 main.ts var start = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);var

爬虫逆向实战(41)-某巢登陆(AES、MD5、RSA、滑块验证码)

一、数据接口分析 主页地址&#xff1a;某巢 1、抓包 通过抓包可以发现在登录时&#xff0c;网站首先请求captcha/querySlideImage/来获取滑块验证码的图片&#xff0c;然后请求captcha/checkCode/接口来验证滑块验证码。滑块验证码校验成功后&#xff0c;请求noshiro/getPu…

使用explain优化慢查询的业务场景分析

问&#xff1a;你最害怕的事情是什么&#xff1f;答&#xff1a;搓澡问&#xff1a;为什么&#xff1f;答&#xff1a;因为有些人一旦错过&#xff0c;就不在了 Explain 这个词在不同的上下文中有不同的含义。在数据库查询优化的上下文中&#xff0c;“EXPLAIN” 是一个常用的 …

矩阵置零解题

给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2&#xff1a; 输入&…

UI(四)布局

文章目录 10、Navigator——路由器组件11、Pannel——可滑动面板12、Refresh——刷新组件13、RelativeContainer——相对布局组件14、Scroll——可滚动容器15、SideBarContainer——侧边栏容器16、Stack——堆叠容器17、Swiper——滑动块视图容器18、Tabs和TabContent——页签和…

mac英语学习工具:Eudic欧路词典 for Mac 激活版

Eudic欧路词典是一款非常受欢迎的英语学习软件&#xff0c;它提供了丰富的词汇解释、例句、同义词、反义词等功能&#xff0c;帮助用户更好地理解和掌握英语单词。 以下是Eudic欧路词典的一些主要特点&#xff1a; 海量词汇库&#xff1a;Eudic欧路词典拥有庞大的词汇库&#…

arm_uart4实验

#include "uart4.h" //UART //初始化 void hal_uart4_init() { //rcc_init //…

Google推出开源模型Gemma 2:性能大幅提升与创新训练方法

引言 近日&#xff0c;Google推出了开源模型Gemma 2&#xff0c;吸引了广大研究人员和开发者的关注。相比上一代模型&#xff0c;Gemma 2在性能和可用性方面实现了显著提升&#xff0c;提供了9B和27B两个版本&#xff0c;并且对外开放免费使用。本文将深入探讨Gemma 2的技术细…

QueryClientProvider is not defined

QueryClientProvider is not defined 运行一个svelte的项目&#xff0c;报错如上&#xff0c;前后查找解决不了&#xff0c;然后没办法&#xff0c; 本来是用yarn 安装的依赖&#xff0c;改用npm install&#xff0c;再次运行就成功了

可燃气体报警器定期检测:优化与改进策略的探讨

在现代化的工业环境中&#xff0c;可燃气体报警器的作用日益凸显。它们像是我们生产现场的安全卫士&#xff0c;时刻警惕着可能发生的危险&#xff0c;确保我们的工作环境安全、稳定。 然而&#xff0c;要确保这些“卫士”始终忠诚可靠&#xff0c;定期检测就显得尤为重要。 …

【JVM面试题】总结-01

【JVM面试题】总结-01 1. 介绍下Java内存区域(运行时数据区)1.1 程序计数器(线程私有)1.2 虚拟机栈(线程私有)1.3 本地方法栈(线程私有)1.4 Java堆(线程共享)1.5 方法区(线程共享)1.5.1 方法区和永久代的关系1.5.2 常用参数1.5.3 为什么要将永久代 (方法区) 替换为元空间 (Meta…

WCCI 2024开幕,横滨圣地巡礼,畅游动漫与美食的世界

惊喜&#xff01;WCCI 2024开幕&#xff0c;横滨圣地巡礼&#xff01;畅游动漫与美食的世界 会议之眼 快讯 会议介绍 IEEE WCCI&#xff08;World Congress on Computational Intelligence&#xff09;2024&#xff0c;即2024年IEEE世界计算智能大会&#xff0c;于6月30日至…

写代码,为什么还需要作图?

引言 古人云 &#xff1a;一图胜千言&#xff0c;闲人说&#xff1a;无图无真相。 在日常的聊天工具当中&#xff0c;无论是使用微信&#xff0c;还是钉钉。使用图片或表情包的频次越来越高&#xff0c;那是为什么呢&#xff1f;其实在互联网没有那么发达的时候&#xff0c;我…