P7 C++指针

news2024/11/15 15:26:34

前言 

指针是一个令很多人都很痛苦的内容,然而指针其实没有大家想象中的那么复杂。

对计算机来说内存就是一切,如果非要我说出编程中最重要的一件事,我可能会说是内存

当你编写了一段程序并启动它时,所有的程序都被载入到内存中,指令告诉计算机在你写的代码中要做什么。所有这些都被加载到内存中,CPU 就是这样访问你的程序并执行它的指令的。

当你创建一个变量,并从磁盘中读取数据时,所有的这些都存储在内存中,如果没有内存就什么也做不了。而指针对于 管理 和 操纵内存 非常重要。

01 指针的概念

其实,指针是一个整数,一种存储内存地址的数字,指针的值就是一串数字,而这数字其实就是一个地址,仅此而已

内存它就像一条很长的直线而不是一大块。内存就像我们现实世界中的一条街,这一条街有开始也有结束,就像一根线一样,线上就是一堆房子, 没有房子是横穿街道的,假设只有这一条街道,一排的房子,我们现在把这个比喻用在电脑上,它只是一条线性的线,在这条直线上的每一所房子都有一个号码和一个空间,号码就是地址,空间是一个字节,我们显然需要一种方法来寻址所有的 byte 来定位我们这条街上所有的房子。

例如,假设某人在网上订了东西想要送货上门,他需要被送到正确的房子里,或者可能有人把东西从他们的房子里取出去,无论哪种操作,你需要能够从这些房子的内存字节中读写,指针就是这些地址,这些地址告诉我们房子在哪里,这是非常重要的,因为我们在代码中所做的几乎所有的事情都是在从内存中读写,当然你完全有可能写一个不使用指针的 C++ 程序,你完全可以这样做。然而指针是非常有用的工具,正如我刚才提到的,内存可能是你拥有的最重要的东西,是计算机可以提供的很重要的资源,它可以被用于做几乎所有的事情,能够对内存有更多的控制至关重要。

再次重申,一个指针只是一个地址,它是一个保存内存地址得到整数虚构

02 第一个指针

我们来创建一个空指针,void 的意思是无类型。

千万记住,一个指针只是一个地址,它只是一个在内存中保存地址的整数,它不需要类型,如果我们给指针一个类型,我们只是说,这个地址的数据,被假设为我们给的类型,除此之外它没有任何意义,它只是一些我们在实际的源代码可以编写的东西,使我们的生活在语法层面上更容易,为了让我们的生活更轻松。

我们当然可以使用指针类型,不过类型不会改变一个指针的实质,——指针只是一个内存地址,它是一个整数。

所以 void 指针 意味看我们现在不关心我们的代码中这个类型是什么类型的,因为我们只想保存一个地址。

我把它称为 pdata,其值设置为0。0 是什么意思?我们给这个指针的内存地址是 0,这是什么意思?

0 实际上不是一个有效的内存地址,内存地址不会一直到 0,这是无效的,这意味着这个指针是无效的,无效指针是完全可以接受的状态,但我要说的是 0 不是一个有效的内存地址,我们不能从内存地址 0 中读取或写入数据,如果我们尝试这样做的话,程序会崩溃,所以 0 意味着没有。

我们也可以这样写。

这种写法实际上是一个 #define,你把鼠标悬浮在上面可以看到,是 #define NULL 0,和我们用 0 是一样的。或者我们也可以用 C++ 关键字 nullptr,这个会在 C++11 里面介绍。

好的,我们设置了我们的第一个指针,它是无类型的,它的内存地址是 0,一点用处没有,但它可能是你能写的最简单一个指针,这可以让我们做一些更有用的事情。

对上面的代码我们做一些解释。

我们创造一个整数变量,当然我们创建的每个变量都有一个内存地址,因为我们需要一个地方来存储这个变量。

如果我想知道这个变量的内存地址,我可以通过使用 & 运算符来做到这一点,如果我在一个已经存在的变量前面加上一个 & 符号,我们实际上是在问这个变量,嘿,你的内存地址是什么?

我们取这个变量的内存地址,把它赋值给指针变量 pdata。

我们现在有了变量 num的内存地址,我们把它存储在另一个变量中。

我们设置一个断点调试一下。


我们可以看变量的值,当代码执行到下面两句时,在下图左框2pdata的值为0x7fffffffdd0c,其实这是一个整形数,不过这个数字代表着存放变量num的值,所以我们查看0x7fffffffdd0c这个地址时,你会发现这个地址的值是num变量的值

    int num = 9;
    pdata = #

将 void 修改为 int 并运行,你会发现实际上没有改变任何变化。(自己去试一下)

Ubuntu 1.84.2Visual Studio Code 下载配置与vscode查看内存Hex Editor插件,简单易懂-CSDN博客

如果你的VScode还不能查看内存,请看上篇博文

03 如何访问指针保存的地址

我们再做一下修改。

假设我想使用我的数据,我有一个指针指向那个数据,现在我想要写入或读取数据,我该如何操作呢?换句话说,我们知道数据在哪里,但是我怎么能访问它呢,这就要靠逆向引用了(指针的 * 运算符通常被称为 dereference 运算符)。

我们有变量 num,指针 pdata指向 num,但是我怎么才能回到这个 num呢? 你可以通过在指针前面插入一个星号来实现这一点,换句话说,我实际上是在逆向引用那个指针,这意味着我现在可以访问我可以读取或写入数据的数据。我们试着这样做一下。

04 表达式必须是指向完整对象类型的指针C/C++(8

因为我们说过这个指针是一个空指针,也就是说,计算机怎么可能将这个值写入到一个 void 指针,它不知道那是什么,这个 10 是 short 类型吗?——两个字节的整数,是 int 类型吗?——四个字节的整数,是 long long 类型吗?—— 8 个字节的整数,它不知道这需要多少字节的数据,我们刚刚说它是 10,但是 10 可以代表任何东西,这个时候就需要类型了,我们需要告诉编译器,这是一个整数,所以是 4 个字节,我们修改一下。

当然,是我们告诉编译器,这是一个整数,编译器自己并不知道这是不是正确的,如果我们犯了错,比如我们说这实际是一个 double,那程序的运行可能就有点麻烦了。

好吧,通过写代码的时候,逆向引用 *指针,我可以访问这个数据,这个例子中,我写入这个数据。

简单地说,我们不知道指针有多大,我们不知道指针指向的数据多大,因为指针并不包含数据,一个指针就是一个整数,它是一个内存地址,就是这样。

 05 不能将 "int *" 类型的值分配到 "short *" 类型的实体

当我将指针pdata的类型改为short *时,编译器会报错,因为不能将 "int *" 类型的值分配到 "short *" 类型的实体,如果我不想改变指针的类型的话,有没有办法可以解决这个问题,答案是可以的,将num的类型直接强转就行

这样就可以解决

06 new & delete

到目前为止,我们一直在栈上直接创建数据,如果我们像上面的例子一样操作,那就是在栈中创建变量(之后我们会讲到栈和堆的内容)。

如果我想在堆上创建一个变量,或许我可以问我们的电脑,嘿,我想让你给我分配一些内存,我想有一定的尺寸(比如 8 个字节),我会这样做。

#include <iostream>
#include <string.h>
int main()
{
    int *pdata = NULL;
    int num = 9;
    pdata =&num;
    *pdata = 10;
    char  *buf= new  char[8];
    memset(buf, 1, 8);
    return 0;
}

上面的代码给我们分配了 8 个字节的内存,并返回一个指向那块内存开始位置的指针,然后我可以使用 memset 的函数,它可以用我们指定的数据填充一段内存块。

memset 接收一个指针,这个指针将会是内存块的开始的指针,然后是将要填入的值,比如 0,最后是应该填入多少字节,我们要 8 个字节。

运行这个程序。在内存视窗可以看到 buffer 位置的连续 8 个字节都为1 。

这个例子中,我们使用了新的关键字 new 申请了堆内存,当我们完成它后,我们也应该删除数据。

我们可以通过键入 delete 完成删除,我们知道它是一个数组,我们使用数组来分配堆内存,所以我们应该使用 delete[ ] 来删除 buf。

这个例子再次强调了,这个指针,我们分配 8 个 char,1 个 char 是一个字节,这样我们就分配了 8 个字节, 我们用来存储数据的指针指向了数据的开头。

07 指针的指针

还有一点我想说的是指针本身是变量,这些变量也存储在内存中,这意味着我们可以得到双指针或三指针,意思可以有指向指针的的指针。这一切可以如何运作呢,好吧,你只要往下一层想,我现在有一个指针指向我的指针,于是我有了一个变量 a 来存储内存地址,它指向另一个变量 b,变量存储变量 c 的内存地址。就这么简单。

在 buffer 的例子中,我们可以创建一个双指针试一下。

#include <iostream>
#include <string.h>
int main()
{
    int *pdata = NULL;
    int num = 9;
    pdata =&num;
    int **pdata1 = &pdata;
    return 0;
}

我回到指针上来,再次强调,它只是存储内存地址的整数 

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

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

相关文章

Presto+Alluxio数据平台实战

数新网络&#xff0c;让每个人享受数据的价值https://xie.infoq.cn/link?targethttps%3A%2F%2Fwww.datacyber.com%2F 一、Presto & Alluxio简介 Presto Presto是由Facebook开发的开源大数据分布式高性能 SQL查询引擎。 起初&#xff0c;Facebook使用Hive来进行交互式查询…

nginx基础篇学习

一、nginx编译安装 1、前往nginx官网获取安装包 下载安装包 2、解压 3、安装 进入安装包 安装准备&#xff1a;nginx的rewrite module重写模块依赖于pcre、pcre-devel、zlib和zlib-devel库&#xff0c;要先安装这些库 安装&#xff1a; 编译&#xff1a; 启动&#xff…

idea自动切换输入法Smart Input

idea搜索后下载 红色表示中文输入法 再ideavim场景下会自动切换成英文非常好用强烈推荐下载一个

堆的实现(堆的插入、堆的删除等)超级全

堆的实现&#xff08;堆的插入、堆的删除等&#xff09;超级全 文章目录 堆的实现&#xff08;堆的插入、堆的删除等&#xff09;超级全一、前期基础知识1.树结构①树的定义②树的相关概念③二叉树④满二叉树和完全二叉树a.满二叉树b.完全二叉树 ⑤二叉树的性质⑥二叉树顺序结构…

「Java开发中文指南」IntelliJ IDEA插件安装(一)

IntelliJ IDEA是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的Java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能是非常强大的。 插件扩展了Intel…

只考数据结构,计算机评级C+,成都信息工程大学考情分析

成都信息工程大学(C) 考研难度&#xff08;☆☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分析&#xff09;、院校概况、24专业目录、23复试详情、各专业考情分析、各科目考情分析。 正文1715字&#xff0c;预计阅读&#xff1a;3分钟 2023考情概况 …

【从浅识到熟知Linux】基本指定之cat、more和less

&#x1f388;归属专栏&#xff1a;从浅学到熟知Linux &#x1f697;个人主页&#xff1a;Jammingpro &#x1f41f;每日一句&#xff1a;写完这篇我要去吃晚饭啦&#xff01;&#xff01; 文章前言&#xff1a;本文介绍cat、more和less指令三种查看文件的用法并给出示例和截图…

格式化输入输出

跟着肯哥&#xff08;不是我&#xff09;学格式化输入输出 C语言格式化输入 在C语言中&#xff0c;格式化输入&#xff08;Formatted Input&#xff09;是一种从标准输入读取数据并按照指定格式进行解析的操作&#xff0c;它主要通过使用标准库函数scanf()来实现格式化输入。 …

Go语言的学习笔记2——Go语言源文件的结构布局

用一个只有main函数的go文件来简单说一下Go语言的源文件结构布局&#xff0c;主要分为包名、引入的包和具体函数。下边是main.go示例代码&#xff1a; package mainimport "fmt"func main() { fmt.Println("hello, world") }package main就是表明这个文件…

计算机毕业设计 基于SpringBoot的无人智慧超市管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解+答疑

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

14.docker部署应用的两种企业实践

1.介绍 1.1 说明 这里仅仅说明一下在企业应用的两种简单实践&#xff0c;并不包含自动化这套东西。这里说的两种实践&#xff0c;是我在工作中不同公司使用的两种部署方式&#xff0c;仅供大家参考。 1.2 两种部署方式 第一种&#xff1a;是把环境和app都一起打成一个镜像&…

Javaweb之前端工程化的详细解析

3 前端工程化 3.1 前端工程化介绍 我们目前的前端开发中&#xff0c;当我们需要使用一些资源时&#xff0c;例如&#xff1a;vue.js&#xff0c;和axios.js文件&#xff0c;都是直接再工程中导入的&#xff0c;如下图所示&#xff1a; 但是上述开发模式存在如下问题&#xff…

力扣每日一道系列 --- LeetCode 206. 反转链表

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构探索 ✅LeetCode每日一道 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 LeetCode 206. 反转链表 思路一&#xff1a;头插 初始化两个指针&#xff0c;cur 和 newhead。…

数据结构与算法介绍

什么是数据结构 定义&#xff1a; 数据结构就是研究数据的存储方式&#xff1b;数据存储的目的是方便后期对数据的再利用&#xff1b;选择合适的方式来存储数据&#xff0c;是数据结构的核心内容。 数据存储结构的选择&#xff1a;取决于两方面&#xff0c;即数据的逻辑结构和…

metersphere 设置定时任务和查看报告

设置定时任务 设置时间 查看执行后的测试报告 查看报告详情

【报错栏】(Vue) Invalid handler for event “click“: got undefined

Property or method "add" is not defined on the instance but referenced during render. 翻译&#xff1a; 属性或方法“add”未在实例上定义&#xff0c;但在渲染期间引用。 Invalid handler for event "click": got undefined 翻译&#xff1a; …

使用VUE3实现简单颜色盘,吸管组件,useEyeDropper和<input type=“color“ />的使用

1.使用vueuse中的useEyeDropper来实现滴管的功能和使用input中的type"color"属性来实现颜色盘 效果&#xff1a; 图标触发吸管 input触发颜色盘 组件代码部分 &#xff1a;<dropper> ---- vueuse使用 <template><div class"sRGBHexWrap fbc…

DGL在异构图上的GraphConv模块

回顾同构图GraphConv模块 首先回顾一下同构图中实现GraphConv的主要思路&#xff08;以GraphSAGE为例&#xff09;&#xff1a; 在初始化模块首先是获取源节点和目标节点的输入维度&#xff0c;同时获取输出的特征维度。根据SAGE论文提出的三种聚合操作&#xff0c;需要获取所…

2023亚太杯数学建模B题完整原创论文讲解

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2023亚太地区数学建模竞赛B题玻璃温室的微气候调控完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 论文共6…

ZC-OFDM模糊函数原理及仿真

文章目录 前言一、ZC 序列二、ZC-OFDM 信号1、OFDM 信号表达式2、模糊函数表达式三、MATLAB 仿真1、MATLAB 核心源码2、仿真结果①、ZC-OFDM 模糊函数②、ZC-OFDM 距离分辨率③、ZC-OFDM 速度分辨率前言 本文进行 ZC-OFDM 的原理讲解及仿真,首先看一下 ZC-OFDM 的模糊函数仿真…