当前位置: 首页 > news >正文

C++初学(11)

不知不觉就第11篇了QWQ

11.1、指针和自由存储空间

之前提到了计算机程序在存储数据时必须跟踪的3个基本属性:

(1)信息存储在何处;

(2)存储的值为多少;

(3)存储的信息时什么类型。

之前我们通过定义一个简单变量,让声明语句指出了值的类型和符号名,让程序为值分配内存,还在内部跟踪该内存单元。

下面来看另一种方法:以指针为基础,指针是一个变量,其存储的是值的地址,而不是值本身。在讨论指针之前,我们只需对变量应用地址运算符(&),就可以获得它的位置。(这个学过C语言的肯定不陌生)下面给一个程序:

#include <iostream>
int main()
{using namespace std;int donuts = 6;double cups = 4.5;cout << "donuts value= " << donuts;cout << " and donuts address = " << &donuts << endl;cout << "cups value = " << cups;cout << " and cups address = " << &cups << endl;return 0;
}

显示地址时,该实现的cout使用十六进制表示法,因为这是常用于描述内存的表示法。在该实现中,donuts的存储位置比cups要低。两个地址的差为0000006FCE94F8C8-0000006FCE94F8C4=4。因为donuts的类型为int,而这种类型使用4个字节。

处理存储数据的新策略刚好相反,将地址视为指定的值,而将值视为派生量。一种特殊类型的变量——指针用于存储值的地址,因此指针名表示的是地址。*运算符被称为间接值或解除引用运算符,将其应用于指针,可以得到该地址处存储的值(这和乘法使用的符号相同;C++会根据上下文确定指的是什么)。

#include <iostream>
int main()
{using namespace std;int updates = 6;int* p_updates;p_updates = &updates;cout << "Values :updates= " << updates;cout << ", *p_updates= " << *p_updates << endl;cout << "Adresses:&updates= " << &updates;cout << ",p_updates= " << p_updates << endl;*p_updates += 1;cout << "Now updates= " << updates << endl;return 0;
}

int变量updates和指针变量p_updates只不过是同一枚硬币的两面。变量updates表示值,并使用&运算符来获取地址;而p_updates表示地址,并使用*运算符来获得值。由于p_updates指向updates,因此*p_updates和updates完全等价,可以使用int变量来使用。

11.1.1、声明和初始化指针

int *p_updates;

这个声明表明*p_updates的类型为int。由于*运算符被用于指针,因此p_updates变量本身必须是指针。我们可以认为p_updates指向int类型,或者该类型是指向int的指针。

一般来说,C程序员使用这种格式:

int *ptr;

这强调*ptr是一个int类型的值。而很多C++程序员使用这种格式:

int* ptr;

这强调的是:int*是一种类型——指向int的指针。

(其实在哪添加空格是自己喜好,对编译器没啥影响,甚至不加也行)

但是如果要声明多个变量,每个指针变量名都需要使用一个*。

可以在声明语句中初始化指针。被初始化的是指针而不是它指向的值。也就是说,下面的语句将pt的值设置为&higgens:

int higgens=6;
int* pt=&higgens;

11.1.2、指针的危险

在C++中创建指针时,计算机将分配用来存放地址的内存,但不会分配用来存储指针所指向数据的内存。为数据提供空间是一定要的步骤。一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。

11.1.3、指针和数字

指针不是整型,虽然计算机通常把地址当作整数看待,但从概念上,整数可以进行运算,而指针运算没有意义,因此不能将整数赋给指针:(那前面的地址举例)

int* pt;
*pt=0000006FCE94F8C8;

在这里,左边是指向int的指针,因此可以赋给地址。但右边是一个整数,这段语句没有告诉程序这个整数是一个地址,因此不能赋值。如果要使用,应通过强制类型转换将数字转换为适当的地址类型:

int* pt;
*pt= (int *)0000006FCE94F8C8;

这样两边都是地址,赋值才有效。

11.1.4、使用new来分配内存

前面我们将指针初始化为变量的地址;变量是在编译时分配的有名称的内存,而指针只是为可以通过名称直接访问的内存提供的一个别名。指针真正的作用时在运行阶段分配未命名的内存以存储值。在C语言中,可以用库函数malloc()来分配内存;在C++中依然可以这么做,但C++有更好的方法——new运算符

在运行阶段为一个int值分配未命名的内存,并使用指针来访问这个值,这里的关键所在是C++的new运算符。程序员要告诉new,需要为哪种数据类型分配内存;new将找到一个长度正确的内存块,并返回该内存块的地址。例子:

int* pn=new int;

new int告诉程序,需要适合存储int的内存。new运算符根据类型来确定需要多少字节的内存。然后它找到这样的内存,并返回其地址。接下来将地址赋给pn,pn是被声明为指向int的指针。现在pn是地址,而*pn是存储在那里的值。为一个数据对象(可以是结构,也可以是基本类型)获得并指定分配内存的通用格式如下:

typeName * pointer_name=new typeName;

#include <iostream>
int main()
{using namespace std;int nights = 1001;int* pt = new int;*pt = 1001;cout << "nights value = ";cout << nights << ":location = " << &nights << endl;cout << "int ";cout << "value = " << *pt << ":location = " << pt << endl;double* pd = new double;*pd = 10000001.0;cout << "double ";cout << "value= " << *pd << ":location= " << pd << endl;cout << "location of pointer pd: " << &pd << endl;cout << "size of pt = " << sizeof(pt) ;cout << ": size of *pt = " << sizeof(*pt) << endl;cout << "size of pd = " << sizeof(pd) ;cout << ": size of *pd = " << sizeof(*pd) << endl;return 0;
}

       

程序说明:该程序使用new分别为int类型和double类型的数据对象分配内存。指针pt和pd指向这两个数据对象,如果没有它们,将无法访问这些内存单元。现在就可以像使用变量那样使用*pt和*pd了。

该程序还指出了必须声明指针所指向的类型的原因之一:地址本身只指出了对象存储地址的开始,而没有指出其类型(使用的字节)。从两个值的地址可以知道,它们都只是数字,并没有提供类型或长度信息。另外指向int的指针长度和double的指针相同,因为它们都是地址。

11.1.5、使用delete释放内存

当需要内存时,可以使用new来请求,而有请求,就会有删除。delete运算符使得在使用内存后,能够将其归还给内存池,能更有效地使用内存。使用delete时,后面要加上指向内存块的指针:

int* pt=new int;
delete pt;

这将释放pt指向的内存,而不会删除指针pt本身。可以将pt重新指向另一个新分配的内存块。一定要配对地使用new和delete;否则将会发生内存泄漏。

注:只能用delete来释放使用new分配的内存,然而对空指针使用delete是安全的。一般来说不能创建两个指向同一个内存块的指针,因为这将增加错误的删除同一个内存块两次的可能性。

11.1.6、使用new来创建动态数组

11.1.6.1、使用new创建动态数组

在C++中,创建动态数组很容易,只要将数组的元素类型和元素数目告诉new即可。必须在类型名后面加上方括号,其中包含元素数目。例如:

int* psome=new int [10];

new运算符返回第一个元素的地址,这个地址被赋给指针psome。当程序使用完new分配的内存块时,应使用delete释放它们。对于使用new创建的数组,应使用另一种格式的delete来释放:

delete [] psome;

方括号告诉程序,应释放整个数组,而不仅仅是指针指向的元素。

使用new和delete时,应遵循下面的规则:

(1)不要使用delete释放不是new分配的内存。

(2)不要使用delete释放同一块内存块两次。

(3)如果使用new[ ]为数组分配内存,应使用delete[ ]来释放。

(4)对空指针应用delete是安全的。

11.1.6.2、使用动态数组

我们使用上面的声明,可以将它看作是一跟指向该元素的手指。假设int占4个字节,则将手指沿正确的方向移动4个字节,手指指向第二个元素。下面做法对学过C语言的会很熟悉:可以使用psome[0]访问第一个元素,第二个元素则可以使用psome[1],以此类推。

#include <iostream>
int main()
{using namespace std;double* p3 = new double[3];p3[0] = 0.2;p3[1] = 0.5;p3[2] = 0.8;cout << "p3[1] is " << p3[1] << ".\n";p3 = p3 + 1;cout << "Now p3[0] is " << p3[0] << " and ";cout << "p3[1] is " << p3[1] << ".\n";p3 = p3 - 1;delete[] p3;return 0;
}

p3=p3+1;

我们不能修改数组名的值。但指针是变量,因此可以修改它的值。上面这个作用是导致p3指向第二个元素而不是第一个,减去1则指向第一个值,便能给delete[ ]提供正确的地址。

相关文章:

C++初学(11)

不知不觉就第11篇了QWQ 11.1、指针和自由存储空间 之前提到了计算机程序在存储数据时必须跟踪的3个基本属性&#xff1a; &#xff08;1&#xff09;信息存储在何处&#xff1b; &#xff08;2&#xff09;存储的值为多少&#xff1b; &#xff08;3&#xff09;存储的信息…...

Vba选择cad中不同类型图元(Select Case True语句和like用法)

Select Case True 是一个常见的VBA编程技巧&#xff0c;用于在多个条件之间进行选择。具体来说&#xff0c;Select Case True 语句的每个 Case 语句都包含一个布尔表达式&#xff0c;这些表达式会逐个与 True 进行比较。当其中一个表达式的结果为 True 时&#xff0c;对应的代码…...

Kafka基本讲解

Kafka基本讲解 一&#xff1a;Kafka介绍 Kafka是分布式消息队列&#xff0c;主要设计用于高吞吐量的数据处理和消息传输&#xff0c;适用于日志处理、实时数据管道等场景。Kafka作为实时数仓架构的核心组件&#xff0c;用于收集、缓存和分发实时数据流&#xff0c;支持复杂的…...

thinkphp6项目初始化配置方案二次修正版本

数据返回统一格式 app/BaseController.php新增文件内容在末尾,并在构造函数中实例化数据模型类 // 成功统一返回格式 function Result($data, $msg , $code 200, $httpCode 200): \think\response\Json {$res [code > $code,msg > $msg,data > $data];return j…...

XXE靶机教学

arp-scan -l主机发现 arp-scan -l 端口扫描 nmap -p- 192.168.48.139 服务探测 nmap -p80,5355 -sT -sC -sV 192.168.48.139 目录扫描 dirsearch -u http://192.168.48.139 访问robots.txt 发现两个可访问路径 burp抓包 测试是否存在xxe漏洞 <?xml version "1.…...

干货 | 2024步入数字化转型深水区,云原生业务稳定性如何保障(免费下载)

云原生业务的稳定性保障是一个涉及多个层面的复杂任务&#xff0c;以下是一些关键措施和策略&#xff0c;以确保云原生业务的高效稳定运行&#xff1a; 一、平台安全性评估与加固 云原生平台安全评估&#xff1a;对云原生平台&#xff08;如Kubernetes、Docker等&#xff09;…...

for(char c:s),std::vector<int> numbers 和std::int numbers[],.size()和.sizeof()区别

在C中当需要对某个容器或数组进行遍历时我们可以使用以下语句&#xff0c;c将会被赋值为s中的元素 for(char c:s)://s可以是任何满足条件的容器或数组for(int c:s):for(double c:s):for(float c:s):在C中我们来区分std::vector numbers {1, 2, 3, 4, 5};和std::int numbers[] …...

桌面云备份可以删除吗?安不安全

桌面云备份可以删除吗&#xff1f;答案是可以的。如果用户不需要这些备份或者想要释放存储空间&#xff0c;桌面云备份是可以进行删除的&#xff0c;并且删除桌面云备份是一个相对安全的过程&#xff0c;但需要注意以下几点来确保操作的安全性和数据的完整性。 一、桌面云备份…...

【爬虫实战】利用代理爬取电商数据

文章目录 前言工具介绍实战获取网站数据编写代码数据展示 推荐总结 前言 当今电商平台正经历着快速的转型与升级。随着技术的进步和用户需求的多样化&#xff0c;电商不仅从简单的在线购物演变为综合性的购物生态系统&#xff0c;还融合了人工智能、大数据和云计算等先进技术。…...

python如何统计列表中元素出现的次数

在 Python 中&#xff0c;可以使用多种方法来统计列表中元素出现的次数。以下是一些常用的方法&#xff1a; 方法 1: 使用 count() 方法 list 对象有一个内置的 count() 方法&#xff0c;可以直接统计某个元素在列表中出现的次数。 my_list [1, 2, 3, 2, 1, 4, 2] count_of…...

【算法】山脉数组的峰顶索引

难度&#xff1a;中等 题目描述&#xff1a; 给定一个长度为 n 的整数 山脉 数组 arr &#xff0c;其中的值递增到一个 峰值元素 然后递减。 返回峰值元素的下标。 你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。 示例 1&#xff1a; 输入&#xff1a;arr [0,1,0]…...

牛客 JZ31.栈的压入,弹出序列 C++写法

牛客 JZ31.栈的压入&#xff0c;弹出序列 C写法 思路&#x1f914;&#xff1a; 创建一个栈&#xff0c;push压入序列&#xff0c;然后用栈顶跟弹出序列比&#xff0c;如果一样就出栈并且继续比较&#xff0c;不一样就再次push入栈&#xff0c;直到压入序列走完&#xff0c;如果…...

PageHelper在Mybatis的一对多表关联时total数错误

最近在学习PageHelper遇到一个bug记录一下&#xff1a; 在Mybatis的一对多表中&#xff0c;PageHelper获取的total是所有的记录数&#xff0c;而不是我想要的第一次sql的记录数。 解决方案1&#xff1a; 不要在mapper层获取一对多关联&#xff0c;在service层先获取一&#…...

(20240806)硫氧镁 / 碱式硫酸镁-混凝土

一、目录 一篇博士论文&#xff0c;5篇硕士论文&#xff0c;南京航空航天大学双一流211&#xff0c;60。余红发团队 具体涉及到 &#xff08;1&#xff09; 碱式硫酸镁水泥的混凝土应用 、&#xff08;一篇博士论文&#xff09; 有微观分析 &#xff08;2&#xff09;混…...

string类的模拟实现(C++)

一、前言 想要模拟实现一个库中的类&#xff0c;那就要首先要熟悉如何使用这个类。建议通过下面博客&#xff0c;完成对Cstring类的学习。 C的string类-CSDN博客 二、模拟实现 我们将从string的成员函数即成员变量入手&#xff0c;模拟实现string类。 成员变量 string类的…...

C++_sizeof的相关知识点

1.指针的大小永远是固定的&#xff0c;取决于处理器位数&#xff0c;32位就是 4 字节&#xff0c;64位就是 8 字节 2.数组作为函数参数时会退化为指针&#xff0c;大小要按指针的计算 int func(char array[]) {printf("sizeof%d\n", sizeof(array));printf("s…...

Istio Proxy的Envoy代理架构中,Upstream提供的功能是:

Istio Proxy的Envoy代理架构中&#xff0c;Upstream提供的功能是&#xff1a; A. 接收来自Envoy连接和请求的主机&#xff0c;并返回响应 B. 连接的一组逻辑相同的上游主机 C. 将下游主机连接到Envoy的主机&#xff0c;用来发送请求并接受响应 选择A Istio Proxy的Envoy代理架…...

LeetCode 热题 HOT 100 (015/100)【宇宙最简单版】

【栈】No. 0155 最小栈【中等】&#x1f449;力扣对应题目指路 希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#xff01; …...

【HarmonyOS】鸿蒙应用实现截屏

【HarmonyOS】鸿蒙应用实现截屏 组件截屏 通过componentSnapshot的get函数&#xff0c;将需要截图的组件设置id传进去即可。 import { componentSnapshot } from kit.ArkUI; import { image } from kit.ImageKit;/*** 截图*/ Entry Component Preview struct SnapShotPage {S…...

Conda包依赖侦探:conda inspect命令全解析

Conda包依赖侦探&#xff1a;conda inspect命令全解析 在Conda环境中&#xff0c;管理包及其依赖关系是一项重要任务。conda inspect命令是一个强大的工具&#xff0c;它可以提供包的详细信息&#xff0c;包括依赖关系、链接、版本等。这对于诊断环境问题、理解包的依赖结构以…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...