c++中引用及指针详解

2023-11-07

1、指针

1.1、什么是指针

指针的本质

通俗来说 指针是一个变量 (保存变量地址的变量)像常见的:

int a=10;

指针与地址

首先 ,我们通过一个简单 的示意图来说明内存是如何组织的。通常机器都有一系列连续编号或编制的存储单元,这些存储单元可以单个进行操作,也可以连续成组的方式操纵。可以这样理解假定一个存储单元是学校的一个宿舍,每个宿舍都会有自己的门牌号,把宿舍楼当做电脑的存储区,想找的一个人,有两种方式(1)直接叫名字(2)直接找到宿舍对应的床位;
通常情况下,机器的一个字节可以存放一个char类型的数据,两个相邻的字节存储单元可存储一个short (短整型)一个long (长整型)组存储单元(通常是2或4个字节)。因此,如果c的类型是char,并且p是指向c的指针,则可用图1.1表示它们之间的关系。
在这里插入图片描述
那么一元运算符&可用于取一个对象的地址:

p=&c;

将把c的地址赋值给变量p,我们称p为“指向”c的指针。地址运算符&只能应用于内存中的对象,即变量与数组元素。它不能作用于表达式、常量或register类型的变量。

程序中如何声明指针以及如何使用运算符&和*

int x=1,y=2,z[10];
int *ip;//ip是指向int类型的指针
ip=&x;//ip指向x
y=*ip;//修改y的值为1
*ip=0;//x的值为0
ip=&z[0]//ip指向z[0]

1.2、指针有什么作用

指针与函数参数

由于C语言是以传值的方式将参数值传递给被调用函数的,因此,被调用函数不能直接修改主调函数中变量的值。例如,排序函数可能会使用一个名为swap的函数来交换两个次序颠倒的元素。但是,如果将swap函数定义为下列形式:

void swap(int x, int y)
{
    int tmp;
    tmp = x;
    x = y;
    y = tmp;
}
int main()
{
    int a = 10, b = 20;
    swap(a, b);
    cout << a << "-----" << b << endl;
    return 0;
}

结果是:
在这里插入图片描述
在这里插入图片描述
可以看出 x y的值会被交换 但是主函数 a b的值不会被修改;
那么,如何实现我们的目标呢?可以使主调程序将指向所要交换的变量的指针传递给被
调用函数:

void swap(int *x, int *y)
{
    int tmp;
    tmp = *x;
    *x = *y;
    *y = tmp;
}
int main()
{
    int a = 10, b = 20;
    cout << a << "-----" << b << endl;
    swap(&a, &b);
    cout << a << "-----" << b << endl;
    return 0;
}

在这里插入图片描述
调动函数前
在这里插入图片描述
调动函数后
在这里插入图片描述
指针还有很多,今儿不讨论这些;

2、引用

2.1、什么是引用

可以这样理解 :引用就是别名;举个例子就是猫可以叫猫也可以叫咪咪;
定义一个变量a赋初值为10;并且给a起一个别名为q;

int a=10;
int &q=a;

在这里插入图片描述
可以看出其实a和q是同一个东西;
引用的底层实现还是指针;

int &q=a;
等价于
int *const q=&a;

证明一下呗;看图。在这里插入图片描述

2.2、引用的规则

1)&在此不是求地址运算,而是起标识作用。
2)类型标识符是指目标变量的类型。
3)声明引用时,必须同时对其进行初始化。
4)引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名。ra=1; 等价于 a=1;
5)声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。故:对引用求地址,就是对目标变量求地址。&ra与&a相等。
6)不能建立数组的引用。因为数组是一个由若干个元素所成的集合,所以无法建立一个数组的别名。
7)不能建立引用的引用,不能建立指向引用的指针。因为引用不是一种数据类型!!所以没有引用的引用,没有引用的指针。

2.3、引用和数组

先看两行代码

int& q[10] ;
//q首先向右结合,所以这个相当于 (int&)q[] q是个数组,其中的元素是引用
//应该叫:引用的数组
int(&p)[10] ;
//p首先和&结合,所以p是引用,引用的对象是数组
//应该叫作数组的引用

眼睛解释的通啊!!!

引用的数组(非法)

可以明确的说明,引用的数组是不能当函数的参数的。再者要说明,这种方式是非法的。
原因:从引用的本质说吧。
首先,引用必须被初始化,而数组并不能被另一个数组初始化或被另一个数组赋值并且因为引用数组的话,就相当于给数组中每个元素引用,没有分配空间。
再次,引用它不支持传统意义的复制,它不占用新的空间。

数组的引用

int main()
{
    int a[10] = { 10,20,30,40,50,60,70,80,90,100 };
   // int& q[10] = a;
    int(&p)[10] = a;
    for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
    {
        cout << p[i] << " ";
    }
    cout << endl;
    cout << "size=" << sizeof(p) << endl;
}

在这里插入图片描述

2.4、为什么要用引用

1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如意的问题。
2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。
3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
4)使用引用的时机。流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。 引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。

3、const修饰符

在C语言中,习惯用#define来定义常量,列如:

#define LIMIT 100

实际上,这种方法只是在预编译阶段进行字符的转换,把程序中出现标识符LIMIT替换为100.在预编译之后,程序不在有LIMIT这个标识符,LIMIT不是变量,没有类型,不占用存储单元,而且容易出错。
C++提供了一种更灵活,更安全的方式来定义常量,即使用const修饰符来定义常量。例如:

const int LIMIT=100;

这个常量是有类型的,占用存储单元,有地址,可以用指针指向它,但不能修改它。
const的作用于#define相似,但是它消除了#define的不安全性。因此c++建议试使用const取代#define定义常量。
说了这么多举个例子呗;

int main()
{
    int a= 1;
    #define T1 a+a
    #define T2 T1-T1
    cout << "T2 is " << T2 << endl;
    return 0;
}

想想答案是多少?0还是2?
在这里插入图片描述
换一下代码试试

int main()
{
    int a= 1;
    int const T1 = a + a;
    int const  T2 = T1 - T1;
    cout << "T2 is " << T2 << endl;
    return 0;
}

在这里插入图片描述
看下面这两个有区别吗?
实际上没有。

const int a=5;
int const a=5;

const会用了吗?继续。。。

3.1、指针与const

(1)通过指针修改值

    int a = 5, b = 10;
    int* q = &a;
    *q = 10;

在这里插入图片描述
在这里插入图片描述
(2)int* const 情况
先搞清楚const限定什么?

int main()
{
    int a = 10, b = 20;
    int* const s = &a;
    s=&b;//错误
    *s=100;//正确
    return 0;
}

const限定的是s的指向也就是说s是个常量;即指向不可以改变不能再去只想别的地址,值可以改变。
继续在来,看代码:

int main()
{
    int a = 10, b = 20;
    int* const s = &a;
    int* p1 = s;
    const int* p2 = s;
    int* const p3 = s;
    const int* const p4 = s;
    return 0;
}

能看出来 那个对那个错吗?
嘿嘿 都对;为什么?
原因就是 s里面存放的是a的地址吧,那也就是说p1他们拿到是a的地址吧,那它有什么错。
(3)const int*
const 限定的是它的值吧即就是*p是个常量吧,和指向没啥子关系;

int main()
{
    int a = 10, b = 20;
    const int *p=&a;
    *p = 100;//错误吧
    p = &b;
    return 0;
}

在这里插入图片描述
在来看看那个错误:

int main()
{
    int a = 10, b = 20;
    const int *s=&a;
    int* p1 = s;//err
    const int* p2 = s;
    int* const p3 = s;//err
    const int* const p4 = s;
    return 0;
}

p1 p3 错误 原因是 p1指向s的话 p1没有被限定 所以说通过*p1就可以改变a的值,*s的能力被扩大化。

3.2、引用与const

int main()
{
    int a = 10;
    int& b = a;
    const int& c = a;
    a += 100;
    b += 100;
    c+=100;//编译出错,因为前面有const进行修饰,所以c不能改变
}

3.3、指针的引用与const 的关系

(1)int *const

int main()
{
    int a = 10, b = 20;
    int* const s = &a;
    int*& p1 = s;//err
    const int*& p2 = s;//err
    int* const& p3 = s;
    const int* const& p4 = s;
    return 0;
}
p1和p2错误的原因一样 就是 s的指向不能修改,而引用就是s的一个别名,所以对p1修改就是对s的修改 s的指向不能被修改但是p1又可以修改 矛盾 ,同是一个东西相煎何太急。。。。

(2)const int *

int main()
{
    int a = 10, b = 20;
    const int* s = &a;
    int*& p1 = s;//err
    const int*& p2 = s;
    int* const& p3 = s;//err
    const int* const& p4 = s;

}

这个不解释 只要 理解引用是它的别名 也就是修改引用和修改它是同一个操作就行了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++中引用及指针详解 的相关文章

  • 通过 SocketCAN 进行 boost::asio

    我正在考虑利用升压阿西奥 http www boost org doc libs 1 49 0 doc html boost asio html从a读取数据套接字CAN http en wikipedia org wiki SocketCA
  • 如何保证对象只有一个线程

    我有以下代码 class Service public void start creates thread which creates window and goes to message loop void stop sends WM C
  • 我如何理解这个 C 类型声明?

    double bar int double double double double 在查看讲座幻灯片时 我发现了留给学生的练习 用简单的英语来说 什么是类型bar在这个 C 声明中 Please帮助我解决这个问题 我什至不知道从哪里开始
  • 在 Xamarin 中隐藏软键盘

    如何隐藏软键盘以便在聚焦时显示Entry在 Xamarin forms 便携式表单项目中 我假设我们必须为此编写特定于平台的渲染器 但以下内容不起作用 我创建自己的条目子类 public class MyExtendedEntry Entr
  • 类特定的新删除运算符是否必须声明为静态

    标准中是否要求类特定的 new new delete 和 delete 是静态的 我可以让它们成为非静态成员运算符吗 为什么需要它们是静态的 它们被隐式声明为静态 即使您没有键入 static
  • 信号处理程序有单独的堆栈吗?

    信号处理程序是否有单独的堆栈 就像每个线程都有单独的堆栈一样 这是在 Linux C 环境中 来自 Linux 手册页signal 7 http kernel org doc man pages online pages man7 sign
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 动态生成的控件 ID 返回为 NULL

    我可以在 Page PreInit 函数中创建动态控件 如何检索控件及其 ID 我的 C 代码用于创建动态控件之一 var btn new WebForms Button btn Text btn ID Addmore btn Click
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行
  • 类的成员复制

    在学习 复制成员 概念时 书中给出了如下说法 此外 如果非静态成员是引用 const 或没有复制赋值的用户定义类型 则无法生成默认赋值 我不太明白这个声明到底想传达什么 或者说这个说法指的是哪一种场景 谢谢 该语句与编译器自动为您编写的类
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • C# 构建一个 webservice 方法,它接受 POST 方法,如 HttpWebRequest 方法

    我需要一个接受 POST 方法的 Web 服务 访问我的服务器正在使用 POST 方法 它向我发送了一个 xml 我应该用一些 xml 进行响应 另一方面 当我访问他时 我已经使用 HttpWebRequest 类进行了管理 并且工作正常
  • 如何从文本文件读取整数到数组

    这就是我想做的 我对此有些不满 但我希望你能容忍我 这对我来说是一个非常新的概念 1 在我的程序中 我希望创建一个包含 50 个整数的数组来保存来自文件的数据 我的程序必须获取用户的文档文件夹的路径 2 文件的名称为 grades txt
  • C++ php 和静态库

    我创建了一个library a 其中包含 cpp 和 h 文件 其中包含很多类 嵌套类和方法 我想在 php 示例中包含这个静态库并尝试使用它 我想提一下 我是 php 新手 我已经在 test cpp 文件中测试了我的 libray a
  • 如何分析组合的 python 和 c 代码

    我有一个由多个 python 脚本组成的应用程序 其中一些脚本正在调用 C 代码 该应用程序现在的运行速度比以前慢得多 因此我想对其进行分析以查看问题所在 是否有工具 软件包或只是一种分析此类应用程序的方法 有一个工具可以将 python
  • ASP.NET MailMessage.BodyEncoding 和 MailMessage.SubjectEncoding 默认值

    很简单的问题 但我在 MSDN 上找不到答案 查找 ASP NET 将用于的默认值 MailMessage BodyEncoding and MailMessage SubjectEncoding 如果你不在代码中设置它们 Thanks F
  • 使用restsharp序列化对象并将其传递给WebApi而不是序列化列表

    我有一个看起来像的视图模型 public class StoreItemViewModel public Guid ItemId get set public List
  • 您是否将信息添加到每个 .hpp/.cpp 文件的顶部? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 创建新的 C 头文件 源文件时 您会在顶部添加哪些信息 例如 您是否添加日期 您的姓名 文件描述等 您是否使用结构化格式来存储此信息 e g F
  • 如何在 DropDownList 中保留空格 - ASP.net MVC Razor 视图

    我在视图中通过以下方式绑定我的模型 问题是我的项目文本是格式化文本 单词之间有空格 如下所示 123 First 234 00 123 AnotherItem 234 00 123 Second 234 00 我想保留此项目文本中的空格 即
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造

随机推荐

  • [论文解读]UNet++解读 + 它是如何对UNet改进 + 作者的研究态度和方式

    UNet 论文 地址 UNet 论文翻译 地址 UNet 源代码 地址 UNet 作者在知乎 上进行了解读 里面还有视频的详解 深入人心 里面的每一句话都令我印象深刻 我总结如下 很多论文给出了他们建议的网络结构 其中包括非常多的细节 比如
  • Oracle常用及非常用函数

    感于总有些网友提出一些非常基础的问题 比如有没有实现某某功能的函数啊 某某函数是做什么用的啊 格式是什么等等 同时也感受到自己对oracle函数认识的不足 于是集中月余时间专注于oracle函数 小有心得不敢私藏 发之与诸公共享 本文并不准
  • Java 使用BufferedImage快速画出图片

    Java 使用BufferedImage快速画出图片 在上一篇文章中我们学习了类似相机中的一些功能 比如黑白 马赛克等 但是我们发现一个问题 画的太慢了 一张图片能画半天 而且还是一条一条的 今天我们来学习如何迅速的画出图片 新知识 new
  • C++ 正则表达式regex(二)

    正则匹配 查找与替代 书写好模式字符串后 需要将待匹配的字符串和模式字符串进行一定规则的匹配 包括三种方式 匹配 regex match 查找 regex search 替换 regex replace 匹配很简单 直接将待匹配字符串和模式
  • PLSQL连接ORACLE时弹出空白框

    前两天一台数据库服务器坏掉了 重新找了台同型号的替换 服务器系统装好后 就在本地机器上远程操作服务器 配置数据库后 新部署的服务就是起不来 怀疑数据库的问题 就各种折腾 还是没有起作用 用本地PLSQL链接ORACLE时 就出现一个小白框
  • HBase选择Store file做compaction的算法

    The algorithm is basically as follows Run over the set of all store files from oldest to youngest If there are more than
  • Maven : Log4j2 could not find a logging implementation

    1 美图 3 错误信息 Log4j2 could not find a logging implementation Please add log4j core to the classpath 解决办法 pom把log4j api也加进去
  • 开源电路仿真软件CircuitJS1介绍与使用入门

    文章目录 前言 基础介绍 使用入门 界面与显示 绘制与操作 保存为文件 子电路绘制与使用 总结 前言 在做电路设计的过程中经常需要用到电路仿真软件对设计的电路进行仿真 以确定电路工作特性或者元件的参数取值 使用电路仿真软件可以缩短电路开发时
  • CentOS系统安装Apache步骤详解

    1 通过 yum y install httpd 安装apache服务 2 使用 systemctl start httpd 启动Apache服务器 并测试启动情况 3 修改主页 4 访问测试 这样 centos的apache服务就搭建好了
  • 单片机毕设 基于stm32的WiFi监控小车

    文章目录 1 背景 2 系统设计方案 2 1 实现功能 2 1 1 硬件部分 2 1 2 软件部分 2 1 3 WIFI通信功能 2 2 系统架构 2 2 1 WiFi 通信 2 2 2 电机驱动 2 2 3 摄像头 2 2 4 舵机 2
  • 合宙Air724UG LuatOS-Air LVGL API控件-图片 (Image)

    图片 Image 图片IMG是用于显示图像的基本对象类型 图像来源可以是文件 或者定义的符号 示例代码 创建图片控件 img lvgl img create lvgl scr act nil 设置图片显示的图像 lvgl img set s
  • C# 执行 .bat 文件

    string path E a bat Process pro new Process FileInfo file new FileInfo path pro StartInfo WorkingDirectory file Director
  • 在react hook里使用mobx(配置mobx依赖)

    在powershell里安装依赖 直接npm i mobx或者npm i mobx react是会报错的 npm i mobx mobx react save save是下载到 dependencies 里 npm i mobx react
  • 图像边缘及matlab实现

    图像边缘是图像的重要特征 是图像中特性 如像素灰度 纹理等 分布的不连续处 图像周围特性有阶跃变化或屋脊状变化的那些像素集合 图像的边缘部分集中了图像的大部分信息 一幅图像的边缘结构与特点往往是决定图像特质的重要部分 图像边缘的另一个定义是
  • Spring Boot + Vue的网上商城之物流系统实现

    Spring Boot Vue的网上商城之物流系统实现 思路 当构建一个物流系统时 我们可以按照以下步骤进行 设计数据模型 首先确定系统中需要存储的数据 例如物流公司信息 物流订单信息等 根据需求设计相应的数据模型 包括实体类和数据库表结构
  • 软件工程考试归纳知识点

    软件工程 第一章 什么是软件 软件是计算机系统中与硬件子系统相互依存的另一个子系统 是一个包含程序及其文档资料的完整集合 提供了用户与硬件子系统之间的接口 软件的特征 1 软件固有的特性 复杂性 抽象性 依赖性 软件使用特性 2 软件生产特
  • Python之可变参数,*参数,**参数,以及传入*参数,进行解包

    1 定义了一个需要两个参数的函数 def print str first second print first print second if name main print str hello world 如果传一个参数调用 print
  • Blink 帮助文档 编译

    个人使用的是Centos7 1 安装rvm 参考 http rvm io rvm install gpg keyserver hkp pool sks keyservers net recv keys 409B6B1796C275462A1
  • Rocksdb Compaction原理

    概述 compaction主要包括两类 将内存中imutable 转储到磁盘上sst的过程称之为flush或者minor compaction 磁盘上的sst文件从低层向高层转储的过程称之为compaction或者是major compac
  • c++中引用及指针详解

    这里写目录标题 1 指针 1 1 什么是指针 指针的本质 指针与地址 程序中如何声明指针以及如何使用运算符 和 1 2 指针有什么作用 指针与函数参数 2 引用 2 1 什么是引用 2 2 引用的规则 2 3 引用和数组 引用的数组 非法