C++中的指针、引用和数组

参考文档:《21天学通C++(第8版)》

C++中对于指针、引用和数组使用时,充斥着 * 、& 、[]符号,对于像我这样的初学者面对这些符号难免会陷入混乱。

当然,C++中对符号 * 、& 、[] 赋予了多重意义也是让人容易混乱的原因。

这篇文章是在《21天学通C++》第8章内容基础上,进行总结和提炼,以方便自己和网友们回顾使用。没有基础的同学,可以参考书籍中第8章内容进行学习。

版本号:C++14

先说说三者的概念:

指针:指针是一个变量,用于存储内存地址。

引用:引用是一个别名,它提供了对变量的另一个名称。一旦引用初始化为一个对象,就不能再改变为指向另一个对象。

数组:数组是一种数据结构,用于存储多个相同类型的元素。

来一个表格总结下三个符号的用法,可以先过目一下,不理解没关系,看完下文回头再看会更清晰:

符号

声明

运算符

*

声明指针

解除引用运算符(获取地址所存储的值)

&

声明引用

引用运算符(获取变量地址)

[]

声明数组

数组下标运算符

一.变量声明

三者在C++中是如何声明的呢:

1.声明指针(*)

PointedType * PointerVariableName;int *pointsToInt = NULL;

在C++中,声明指针有三种方式,且都是合法的,可以根据自己的喜好选择其中一种:

int* p
int *p
int * p

2.声明引用(&)

VarType original = Value; 
VarType& ReferenceVariable = original;int original = 30;
int& ref1 = original;

同样引用的声明也有三种方式:

int& ref
int &ref
int & ref

3.声明数组([])

// elements为数组长度
type name[elements];int myNumbers [5];

分别用三种符号对三者进行了声明。让我们造成困惑的是,这三种符号,在表达式中还可以作为运算符来使用。

二.表达式中的运算符

在表达式中,这些运算符的使用场景:

1.引用运算符(&)

&作为运算符还有个场景是 "按位AND" 运算,这里不做介绍

获取变量地址,用指针来存储地址。(引用运算符也叫地址运算符)

// 定义一个变量
int a = 10;
// 定义一个指向int类型的指针,并初始化地址
int* pointer = &a;

2.解除引用运算符(*)

*还有个作用是乘法运算符,这里不做介绍

解引用运算符用于访问指针所指向的内存地址中存储的值。(解除引用运算符也叫间接运算符)

int age = 30; int* pointsToInt = &age;
// 打印指针地址指向的内存中的值(*pointsToInt)
cout << "*pointsToInt = " << dec << *pointsToInt << endl;

将解除引用运算符(*)用于指针时,如果指针未初始化,它所在的内存单元将包含随机值,此时对其解除引用可能会导致程序崩溃或产生意外结果。

3.数组下标运算符([])

用于访问数组中的元素。下标运算符使用方括号 [],并且可以用于一维数组和多维数组。

int arr[5] = {1, 2, 3, 4, 5};
int x = arr[2];  // 获取数组arr中索引为2的元素,即第3个元素

三.其他注意事项

1.动态分配内存和释放

使用new关键字来动态申请内存,如果成功,将返回一个指针,指向分配的内存

delete对动态申请的内存进行释放

Type* Pointer = new Type; // request memory for one element
Type* Pointer = new Type[numElements]; // request memory for numElementsdelete Pointer; // release memory allocated above
delete[] Pointer; // release block allocated above

2.const用于指针

关键字const在指针前修饰,可以对指针指向的地址地址指向的数据能否修改进行限制。

限制

例子

允许✔️

不允许❌

常量指针

指针本身为常量,指向地址不能修改,但可修改指针指向的数据

int daysInMonth = 30;

int* const pDaysInMonth = &daysInMonth;

*pDaysInMonth = 31;

(int daysInLunarMonth = 28; )

pDaysInMonth = &daysInLunarMonth;

指向常量的指针

指针指向的数据为常量不能修改,但可以修改指针包含的地址,即指针可以指向其他地方

int hoursInDay = 24;

const int* pointsToInt = &hoursInDay;

int monthsInYear = 12;

pointsToInt = &monthsInYear;

*pointsToInt = 13;

int* newPointer = pointsToInt;(不允许负值给非const变量)

指向常量的常量指针

指针包含的地址以及它指向的值都不能修改(这种组合最严格)

int hoursInDay = 24;

const int* const pHoursInDay = &hoursInDay;

*pHoursInDay = 25;

int daysInMonth = 30;

pHoursInDay = &daysInMonth;

将指针传递给函数时,这些形式的 const 很有用。函数参数应声明为最严格的 const 指针,以确保函数不会修改指针指向的值。这可禁止程序员修改指针及其指向的数据。

3.数组和指针

数组名是一个指针,指向第一个元素。由于数组变量就是指针,因此也可将用于指针的解除引用运算符(*)用于数组。同样,可将数组下标运算符([])用于指针。

int main() 
{ const int ARRAY_LEN = 5; // 有5个元素的静态数组int myNumbers[ARRAY_LEN] = {24, -1, 365, -999, 2011}; // 指向数组第一个元素的指针int* pointToNums = myNumbers; // 打印数组中的元素cout << "Display array using pointer syntax, operator*" << endl; for (int index = 0; index < ARRAY_LEN; ++index) cout << "Element " << index << " = " << *(myNumbers + index) << endl; cout << "Display array using ptr with array syntax, operator[]" << endl; for (int index = 0; index < ARRAY_LEN; ++index) cout << "Element " << index << " = " << pointToNums[index] << endl; return 0; 
}

数组的限制:

数组类似于在固定内存范围内发挥作用的指针。可将数组赋给指针,但不能将指针赋给数组,因为数组是静态的,不能用作左值。

4.引用

引用是变量的别名。声明引用时,需要将其初始化为一个变量,因此引用只是另一种访问相应变量存储的数据的方式。

引用可以使用在函数的参数中,当参数占用内存过大时,形参的复制步骤会有很大开销,引用的使用可以避免这种开销浪费。

ReturnType DoSomething(Type& parameter);

下面解释一下引用传递为何可以避免开销浪费:

C++中有两种参数传递方式:值传递引用传递

在值传递中,C++会在内存中创建该值的一个拷贝,并将这个拷贝传递给函数。这意味着函数内部对参数的修改不会影响到原始值。如下是值传递的例子:

#include <iostream>
using namespace std;void modifyValue(int x) {x = 10;
}int main() {int num = 5;modifyValue(num);cout << num;  // 输出为5,因为函数内部对参数的修改不会影响原始值return 0;
}

使用引用传递,可以避免创建拷贝,还可以直接操作原始值。如下是引用传递参数的例子:

#include <iostream>
using namespace std;void modifyValue(int &x) {x = 10;
}int main() {int num = 5;modifyValue(num);cout << num;  // 输出为10,因为函数内部直接修改了原始值return 0;
}

将const 用于引用,可以限制通过引用修改它指向的变量的值:

int original = 30; 
const int& constRef = original; 
constRef = 40; // 无法通过编译

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

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

相关文章

C //练习 6-5 编写函数undef,它将从由lookup和install维护的表中删除一个变量及其定义。

C程序设计语言 &#xff08;第二版&#xff09; 练习 6-5 练习 6-5 编写函数undef&#xff0c;它将从由lookup和install维护的表中删除一个变量及其定义。 注意&#xff1a;代码在win32控制台运行&#xff0c;在不同的IDE环境下&#xff0c;有部分可能需要变更。 IDE工具&am…

Java http 响应式请求和非响应式请求有什么区别

在Java中&#xff0c;HTTP的响应式请求和非响应式请求有以下区别&#xff1a; HTTP协议本身并不直接支持响应式请求&#xff0c;因为HTTP是基于请求-响应模型的。然而&#xff0c;可以通过使用其他技术和协议来实现响应式请求。 响应方式&#xff1a;响应式请求是指使用响应式编…

SpringBoot 调用错:getWriter() has already been called for this response

这个错误通常表明您尝试从Spring MVC返回一个已使用的HttpServletResponse对象。 原因&#xff1a;这可能是由于直接调用HttpServletResponse的getWriter()或getOutputStream()方法&#xff0c;或者由于在控制器方法中抛出异常而自动调用HttpServletResponse的write()方法。 修…

第10章_多线程扩展练习(Thread类中的方法,线程创建,线程通信)

文章目录 第10章_多线程扩展练习Thread类中的方法1、新年倒计时 线程创建2、奇偶数输出3、强行加塞4、奇偶数打印5、龟兔赛跑友谊赛6、龟兔赛跑冠军赛7、多人过山洞8、奇偶数连续打印9、字母连续打印 线程通信10、奇偶数交替打印11、银行账户-112、银行账户-2 第10章_多线程扩展…

协方差矩阵自适应调整的进化策略(CMA-ES)

关于CMA-ES&#xff0c;其中 CMA 为协方差矩阵自适应(Covariance Matrix Adaptation)&#xff0c;而进化策略&#xff08;Evolution strategies, ES&#xff09;是一种无梯度随机优化算法。CMA-ES 是一种随机或随机化方法&#xff0c;用于非线性、非凸函数的实参数&#xff08;…

SparkSQL——DataFrame

DataFrame Dataframe 是什么 DataFrame 是 SparkSQL中一个表示关系型数据库中 表的函数式抽象, 其作用是让 Spark处理大规模结构化数据的时候更加容易. 一般 DataFrame可以处理结构化的数据, 或者是半结构化的数据, 因为这两类数据中都可以获取到 Schema信息. 也就是说 DataFra…

数据结构之tuple类

前言 tuple 是元组类。tuple 就很有意思了&#xff0c;它和上一篇文章介绍的list 十分相似&#xff0c;都是线性表。最大的不同就是list 可以改变&#xff0c;而tuple 是不可变的。元组就像是列表的补充&#xff0c;我们甚至可以这么理解&#xff1a;元组就是只读的列表。 1.…

自动驾驶模拟器

目录 Carla 自动驾驶模拟器 Udacity自动驾驶模拟器 Carla 自动驾驶模拟器 pip install carla 需要下载地图 Udacity自动驾驶模拟器

一文带你揭秘淘宝终端技术

作者&#xff1a;周杰&#xff08;寻弦&#xff09; 在这个数字化迅速发展的时代&#xff0c;技术的每一次飞跃都不仅仅意味着一个产品的升级&#xff0c;更是对未来世界的一次大胆想象。从 PC 到 iPhone&#xff0c;从 Model 3 到 ChatGPT&#xff0c;都引领了全新的一个行业。…

智慧校园大数据平台功能模块

学校概况模块 智慧校园大数据平台的“学校概况”模块,主要给学校和院系领导使用,能够从宏观、全局把控学校教学、管理、科研、资产等各个方面的整体情况,可以预测学校的发展趋势并且给出决策建议。 比如在消费方面,校领导可以看到近一个月的消费金额和地点的情况,也可以…

AttributeError: module ‘openai‘ has no attribute ‘error‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

我的创作纪念日(730天)

机缘 不知不觉来到CSDN已经730天了&#xff0c;这两年来我收获丰富&#xff0c;从原本的只是从CSDN获取知识&#xff0c;到现在的传播知识&#xff0c;我感觉受益良多&#xff0c;一年多的沉淀&#xff0c;让我在这三个月中绽放&#xff0c;粉丝也从原本的两位数到现在的四千&…

【人工智能与深度学习】当输入层维度为1024,输出层维度为100时,为什么全连接层参数量为1024*100+100

当输入层维度为1024&#xff0c;输出层维度为100时&#xff0c;为什么全连接层参数量为1024*100100 在神经网络中&#xff0c;全连接层&#xff08;也称为稠密层或线性层&#xff09;的参数量计算通常包括权重&#xff08;weights&#xff09;和偏置&#xff08;biases&#x…

【ES6】解构语句中的冒号(:)

在解构赋值语法中&#xff0c;冒号&#xff08;:&#xff09;的作用是为提取的字段指定一个新的变量名。 让我们以示例 const { billCode: code, version } route.query 来说明&#xff1a; { billCode: code, version } 表示从 route.query 对象中提取 billCode 和 version…

每日一记:一个windows的bat脚本工具集

最近在工作上遇到要校验文件的问题&#xff0c;例如&#xff0c;下载了一个文件之后&#xff0c;通过查看文件的md5来校验文件是否完整&#xff0c;这个动作在linux上很简单&#xff0c;但在windows上也不难&#xff0c;可以通过 certutil 命令实现&#xff0c;该命令通常可用于…

SpringBoot项目如何优雅的实现操作日志记录

SpringBoot项目如何优雅的实现操作日志记录 前言 在实际开发当中&#xff0c;对于某些关键业务&#xff0c;我们通常需要记录该操作的内容&#xff0c;一个操作调一次记录方法&#xff0c;每次还得去收集参数等等&#xff0c;会造成大量代码重复。 我们希望代码中只有业务相关…

【论文阅读笔记】4篇Disentangled representation learning用于图像分割的论文

4篇应用解耦表示学习的文章&#xff0c;这里只关注如何解耦&#xff0c;更多细节不关注&#xff0c;简单记录一下。 1.Robust Multimodal Brain Tumor Segmentation via Feature Disentanglement and Gated Fusion Chen C, Dou Q, Jin Y, et al. Robust multimodal brain tum…

PDF 文档解除密码

PDF 文档解除密码 1. 文件 -> 文档属性 -> 安全 -> 文档限制摘要2. PDF365References 1. 文件 -> 文档属性 -> 安全 -> 文档限制摘要 密码保护《算法设计与分析基础_第3版.pdf》 2. PDF365 https://www.pdf365.cn/ 免费功能 -> PDF 去密码 开始去除 Re…

wireshark使用教程

目录 windows平台安装Wireshark组件选择Additional TasksPacket CaptureUSB CaptureNpcap Installation Options Ubuntu上安装 Wireshark不使用 sudo 运行 Wireshark 使用GUI抓包使用命令行抓包确定抓取哪个网卡的报文抓取数据包停止抓包设置过滤条件 参考资料 Wireshark 是一款…

保姆级ESP-IDF开发环境搭建

1. 手动安装工具链&#xff0c;命令行方式&#xff08;windows&#xff09; 1.1 下载离线安装器 进入乐鑫 ESP-IDF Windows Installer Download 下载页面&#xff0c;选择离线版本工具&#xff08;网络原因&#xff0c;安装过程中使用github下载会出问题&#xff09;。 1.2 使…