【C++基础】10. 指针

文章目录

  • 【 1. 指针的定义 】
  • 【 2. 指针的调用 】
  • 【 3. NULL 空指针 】
  • 【 4. 指针的算术运算 】
    • 4.1 指针的递加
    • 4.2 指针的递减
    • 4.3 指针的比较
  • 【 5. 指针与数组 】
    • 5.1 通过指针操作数组
    • 5.2 指针数组、数组指针
  • 【 6. 指向指针的指针(多级间接寻址)】
  • 【 7. 传递指针给函数 】
  • 【 8. 函数返回指针 】

  • 指针的作用:通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。
  • 内存和指针的关系:每一个变量都有一个内存位置(理解为:每一个变量在内存中都占有一个位置 / 占用一定内存空间),每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。 内存位置相当于房间,地址相当于门牌号

【 1. 指针的定义 】

  • 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
  • 不同数据类型的指针都是一个代表内存地址的长的十六进制数 。唯一的不同是,指针所指向的变量或常量的数据类型不同。
  • 指针变量声明的一般形式为:
    • type 是指针的基类型,它必须是一个有效的 C++ 数据类型;
    • 用来声明指针的星号 * 与乘法中使用的星号是相同的,但在这个语句中,星号用来指定一个变量是指针;
    • var-name 是指针变量的名称。
type *var-name;
  • 实例:有效的指针声明:
int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch;    /* 一个字符型的指针 */

【 2. 指针的调用 】

  • 使用指针时会频繁进行以下几个操作:① 定义一个指针变量② 把变量地址赋值给指针③ 访问指针变量中可用地址的值。这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。
#include <iostream>
using namespace std;int main ()
{int  var = 20;   // 实际变量的声明int  *ip;        // 指针变量的声明ip = &var;       // 在指针变量中存储 var 的地址cout << "Value of var variable: ";cout << var << endl;// 输出在指针变量中存储的地址cout << "Address stored in ip variable: ";cout << ip << endl;// 访问指针中地址的值cout << "Value of *ip variable: ";cout << *ip << endl;return 0;
}

在这里插入图片描述

【 3. NULL 空指针 】

  • 在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值(即指向地址为0的内存)是一个良好的编程习惯。赋为 NULL 值的指针被称为 空指针
  • NULL 指针是一个定义在标准库中的值为零的常量。
  • 地址为0的内存 在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而 指向内存地址 0的NULL空指针表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
  • 实例:
#include <iostream>using namespace std;int main ()
{int  *ptr = NULL; // ptr为NULL指针,指向地址为0的内存cout << "ptr 的值是 " << ptr ;if 0  // 测试查看ptr指向的值,报错说明地址为0的内存不可访问cout << "*ptr 的值是 " << *ptr ;endreturn 0;
}

在这里插入图片描述

  • 检查一个指针是否是空指针:
if(ptr)     /* 如果 ptr 非空,则完成 */
if(!ptr)    /* 如果 ptr 为空,则完成 */
  • NULL指针的意义:很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。因此, 如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以 防止误用一个未初始化的指针

【 4. 指针的算术运算 】

  • 指针的值表示地址,但归根到底还是一个变量。因此,我们可以对指针执行算术运算。
  • 可以对指针进行四种算术运算:++、- -、+、-。
  • 指针运算的基本单元 = 指针指向变量的数据类型所占字节大小
  • 假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,我们对该指针执行下列的算术运算:ptr++;
    在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。
  • 如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

4.1 指针的递加

  • 实例:下面的程序递增变量指针,以便顺序访问数组中的每一个元素
#include <iostream>using namespace std;
const int MAX = 3;int main ()
{int  var[MAX] = {10, 100, 200};int  *ptr;// 指针中的数组地址ptr = var;for (int i = 0; i < MAX; i++){cout << "Address of var[" << i << "] = ";cout << ptr << endl;cout << "Value of var[" << i << "] = ";cout << *ptr << endl;// 移动到下一个位置ptr++;}return 0;
}

在这里插入图片描述

4.2 指针的递减

    • 实例:下面的程序递减变量指针,以便顺序访问数组中的每一个元素。
#include <iostream>using namespace std;
const int MAX = 3;int main ()
{int  var[MAX] = {10, 100, 200};int  *ptr;// 指针中最后一个元素的地址ptr = &var[MAX-1];for (int i = MAX; i > 0; i--){cout << "Address of var[" << i << "] = ";cout << ptr << endl;cout << "Value of var[" << i << "] = ";cout << *ptr << endl;// 移动到下一个位置ptr--;}return 0;
}

在这里插入图片描述

4.3 指针的比较

  • 指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
  • 下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:
#include <iostream>using namespace std;
const int MAX = 3;int main ()
{int  var[MAX] = {10, 100, 200};int  *ptr;// 指针中第一个元素的地址ptr = var;int i = 0;while ( ptr <= &var[MAX - 1] ){cout << "Address of var[" << i << "] = ";cout << ptr << endl;cout << "Value of var[" << i << "] = ";cout << *ptr << endl;// 指向上一个位置ptr++;i++;}return 0;
}

在这里插入图片描述

【 5. 指针与数组 】

5.1 通过指针操作数组

  • 我们经常在程序中使用指针存储数组首元素的地址,即指针指向数组首元素。这是因为 指针作为一个变量可以递增,而 数组名本身就是一个常指针,不能赋值
#include <iostream>using namespace std;
const int MAX = 3;int main ()
{int  var[MAX] = {10, 100, 200};int *ptr;ptr= var;for (int i = 0; i < MAX; i++){ if (1) // 正确的 {cout<< *ptr <<endl;ptr++;}else // 错误的{cout<< *var  <<endl; //var++; // 数组名是常指针,不能被赋值}}return 0;
}

在这里插入图片描述

  • 通过指针修改数组元素值
*(var + 2) = 500;

5.2 指针数组、数组指针

  • 详见文章:指针数组、数组指针

【 6. 指向指针的指针(多级间接寻址)】

  • 指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时, 第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的地址
  • 一个指向指针的指针变量必须如下声明,即 在变量名前放置两个星号。如下声明了一个指向 int 类型指针的指针:
int **var;
  • 实例:当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号运算符:
#include <iostream>using namespace std;int main ()
{int  var;int  *ptr;int  **pptr;var = 3000;// 获取 var 的地址ptr = &var;// 使用运算符 & 获取 ptr 的地址pptr = &ptr;// 使用 pptr 获取值cout << "var 值为 :" << var << endl;cout << "*ptr 值为:" << *ptr << endl;cout << "**pptr 值为:" << **pptr << endl;return 0;
}

在这里插入图片描述

【 7. 传递指针给函数 】

  • C++ 允许我们传递指针给函数,只需简单地声明函数参数为指针类型即可。
  • 指针作为函数形参时,若在函数内部改变了指针所指向变量的值,则调用完该函数后该变量的值也会变化,因为这是直接对指针所指向的内存地址中的数据进行操作的。
  • 实例
#include <iostream>
#include <ctime>using namespace std;
void getSeconds(unsigned long *par)
{// 获取当前的秒数*par = time( NULL );return;
}int main ()
{unsigned long sec;getSeconds( &sec );// 输出实际值cout << "Number of seconds :" << sec << endl;return 0;
}

在这里插入图片描述

  • 实例:数组名作为函数形参
#include <iostream>
using namespace std;// 函数声明
double getAverage(int *arr, int size);int main ()
{// 带有 5 个元素的整型数组int balance[5] = {1000, 2, 3, 17, 50};double avg;// 传递一个指向数组的指针作为参数avg = getAverage( balance, 5 ) ;// 输出返回值cout << "Average value is: " << avg << endl; return 0;
}double getAverage(int *arr, int size)
{int    i, sum = 0;       double avg;          for (i = 0; i < size; ++i){sum += arr[i];}avg = double(sum) / size;return avg;
}

在这里插入图片描述

【 8. 函数返回指针 】

  • 从函数返回指针,一般形式:
int * myFunction()
{...
}
  • C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量
  • 实例:生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:
#include <iostream>
#include <ctime>
#include <cstdlib>using namespace std;// 要生成和返回随机数的函数
int * getRandom( )
{static int  r[10];// 设置种子srand( (unsigned)time( NULL ) );for (int i = 0; i < 10; ++i){r[i] = rand();cout << r[i] << endl;}return r;
}// 要调用上面定义函数的主函数
int main ()
{// 一个指向整数的指针int *p;p = getRandom();for ( int i = 0; i < 10; i++ ){cout << "*(p + " << i << ") : ";cout << *(p + i) << endl;}return 0;
}

在这里插入图片描述

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

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

相关文章

B树、B+树详解

B树 前言   首先&#xff0c;为什么要总结B树、B树的知识呢&#xff1f;最近在学习数据库索引调优相关知识&#xff0c;数据库系统普遍采用B-/Tree作为索引结构&#xff08;例如mysql的InnoDB引擎使用的B树&#xff09;&#xff0c;理解不透彻B树&#xff0c;则无法理解数据…

Ubuntu 23.10 Beta 镜像开放下载

导读Canonical放出了 Ubuntu 23.10 Beta 镜像&#xff0c;此外 Edubuntu、Kubuntu、Lubuntu、Ubuntu Budgie、Ubuntu Cinnamon、Ubuntu Kylin、Ubuntu MATE、Ubuntu Studio、Ubuntu Unity 和 Xubuntu 等风味版本也同步放出镜像。 近日消息&#xff0c;Canonical 放出了 Ubuntu …

LoRA 是如何工作的?

概述 纯笔记 LoRA的原理 LoRA其实是对稳定扩散模型最关键的部分进行了微小的改变。 这个关键的部分叫&#xff1a;cross-attention layers – 交叉注意力层。 研究人员发现&#xff0c;对这关键部分进行微调就足以实现良好的训练。 上面黄色部分&#xff0c;QKV 部分就是&a…

K8S:Rancher管理 Kubernetes 集群

文章目录 一.Rancher 简介1.Rancher概念2.Rancher 和 k8s 的区别 二.Rancher 安装及配置1.安装 rancher2.登录 Rancher 平台3.Rancher 管理已存在的 k8s 集群4.Rancher 部署监控系统5.使用 Rancher 仪表盘管理 k8s 集群 三.拓展1.Rancher和kubesphere相比较2.K3S和K8S相比较 一…

Opencv——颜色模型+通道分离与合并

视频加载/摄像头调用 VideoCapture允许一开始定义一个空的对象 VideoCapture video VideoCapture(const String &filename,int apiPreferenceCAP_ANY) filename:读取的视频文件或者图像序列名称 apiPreference:读取数据时设置的属性&#xff0c;例如编码格式、是否调用Op…

转化限制+分析变量变化引起的答案变化:Gym - 104065D

https://vjudge.net/contest/587311#problem/H 先转化一波条件&#xff1a; p i ≥ 1 X p_i\ge \frac 1 X pi​≥X1​ p i ≤ 1 1 − Y p_i\le \frac 1 {1-Y} pi​≤1−Y1​ 所以我们按 p p p 排序&#xff0c; s u m x sum_x sumx​ 必然是后缀&#xff0c; s u m y sum_y …

线性回归原理

1、 线性回归的原理 1.1 线性回归应用场景 房价预测 销售额度预测 金融:贷款额度预测、利用线性回归以及系数分析因子1.2 什么是线性回归 1.2.1定义与公式 线性回归(Linear regression)是利用回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的…

VMware和Debian下载

文章目录 ⭐️写在前面的话⭐️一、VMware二、Debain三、建立虚拟机&#x1f680; 先看后赞&#xff0c;养成习惯&#xff01;&#x1f680;&#x1f680; 先看后赞&#xff0c;养成习惯&#xff01;&#x1f680; ⭐️写在前面的话⭐️ CSDN主页&#xff1a;程序员好冰 目前在…

模型UV纹理设置工具

1、什么是模型UV纹理&#xff1f; 模型的UV纹理是将二维纹理图映射到三维模型表面的过程。UV纹理可以为模型赋予颜色、纹理、细节和其他效果&#xff0c;使其看起来更加逼真。 2、UV纹理的原理 下面是模型UV纹理的详细原理介绍&#xff1a; UV坐标系统&#xff1a;UV坐标系统…

乐器经营商城小程序的作用是什么

乐器产品覆盖的人群非常广&#xff0c;小学生、老年人都有不小需求&#xff0c;也因此市场中的从业商家相对较多&#xff0c;产品丰富可供消费者选购&#xff0c;然而在实际经营中&#xff0c;线上线下面临痛点不少。 通过【雨科】平台搭建乐器小程序商城&#xff0c;将所有产品…

DarkGate恶意软件通过消息服务传播

导语 近日&#xff0c;一种名为DarkGate的恶意软件通过消息服务平台如Skype和Microsoft Teams进行传播。它冒充PDF文件&#xff0c;利用用户的好奇心诱使其打开&#xff0c;进而下载并执行恶意代码。这种攻击手段使用了Visual Basic for Applications&#xff08;VBA&#xff0…

JavaSE学习值之--认识异常

&#x1f495;"有效知识的前提是承认知识边界&#xff0c;承认我们对边界那边的一切无可奉告。"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;JavaSE学习值之--认识异常 一.什么是异常&#xff1f; 异常就是程序在运行的时候产生的不正常的行为 …

多机器人三角形编队的实现

文章目录 前言一、机器人编队前的准备二、配置仿真环境2.编写机器人编队.cpp文件 三、三角形编队测试 前言 前阵子一直想要实现多机器人编队&#xff0c;找到了很多开源的编队代码&#xff0c;经过好几天的思索&#xff0c;终于实现了在gazebo环境中的TB3三角形机器人编队。 一…

SQL Server远程登录失败

SQL Server远程登录失败 检查SQL SERVER 是否允许远程访问. 具体步骤: 1)在远端SQL Server主机上,打开SSMS并连接数据库 2)在相应”数据库”上单击右键,选择”属性” 3)选择”连接”选项卡,检查”远程服务器连接”下,RPC服务是否选择. 设置SQL Server相关TCP连接 1.打开SQL Se…

Netty 入门 — 亘古不变的Hello World

这篇文章我们正式开始学习 Netty&#xff0c;在入门之前我们还是需要了解什么是 Netty。 什么是 Netty 为什么很多人都推崇 Java boy 去研究 Netty&#xff1f;Netty 这么高大上&#xff0c;它到底是何方神圣&#xff1f; 用官方的话说&#xff1a;Netty 是一款异步的、基于事…

KMP 算法 + 详细笔记

给两个字符串&#xff0c;T"AAAAAAAAB"&#xff0c;P"AAAAB"; 可以暴力匹配&#xff0c;但是太费时和效率不太好。于是KMP问世&#xff0c;我们一起来探究一下吧&#xff01;&#xff01;&#xff01; &#xff08;一&#xff09;最长公共前后缀 D[i] p[…

Java架构师缓存性能优化

目录 1 缓存的负载策略2 缓存的序列化问题3 缓存命中率低4 缓存对数据库高并发访问5 缓存数据刷新的策略5.1. 实时策略5.2. 异步策略5.3. 定时策略6 何时写缓存7 批量数据来更新缓存8 缓存数据过期的策略9 缓存数据如何恢复10 缓存数据如何迁移11 缓存冷启动和缓存预热想学习架…

解决react样式组合时css module动态样式失效的问题

现象&#xff1a; <button disabled{invalid} className{ "btn btn-primary btn-lg" invalid ? styles.btnDisabled : "" } > 注册 </button> 上面采用字符串拼接的方式&#xff0c;组合class&#xff0c;但是css module的动态样式style…

【Java零基础入门到就业】第一天:java简介和cmd窗口的一些常见命令

1、java简介 Java是一种基于类的、面向对象的编程语言&#xff0c;它被设计成具有尽可能少的实现依赖。它旨在让应用程序开发人员编写一次&#xff0c;并在任何地方运行(WORA)&#xff0c;这意味着编译后的Java代码可以在所有支持Java的平台上运行&#xff0c;而无需重新编译。…

【具身智能模型1】PaLM-E: An Embodied Multimodal Language Model

论文标题&#xff1a;PaLM-E: An Embodied Multimodal Language Model 论文作者&#xff1a;Danny Driess, Fei Xia, Mehdi S. M. Sajjadi, Corey Lynch, Aakanksha Chowdhery, Brian Ichter, Ayzaan Wahid, Jonathan Tompson, Quan Vuong, Tianhe Yu, Wenlong Huang, Yevgen C…