上周,学弟在一个面试中,被考官问到了有关指针的问题。然鹅,学弟说了半天,最终也没能让考官满意。为此我还替他捏了一把冷汗!鉴于此,今天我来写一篇关于指针的初级干货,让你在面试官前有得扯,并扯清楚

文章目录

  • 1. 初识指针
    • (1) 声明指针
    • (2) 使用 & 获取变量地址
    • (3) 使用指针存储地址
    • (4) 使用 * 访问指向的数据
  • 2. 动态内存分配
    • (1) new/delete动态分配和释放内存
    • (2) 带关键字const的指针
    • (3) 指针 VS 数组
  • 3. 使用指针时的常见错误
    • (1) 内存泄漏
    • (2) 无效指针

1. 初识指针

什么是指针呢?想想,我们脑海里的指针大概长什么样:


这样?那我们今天就来聊一聊“指针”表的使用方法吧!


咳咳,不开玩笑了!
在编程语言中,指针可比你上面能看到的“指针”抽象得多。所以在学习时,我们往往知道有指针这么个东西,但是又迷迷糊糊不知道怎么用它。下面,我就来带大家直观地感受一下什么是指针!

简单来说,指针是一种特殊的变量。特殊在于,这种变量存储的不是普通值(比如1,2,100,‘q’);它存储的是内存地址,比如0x101、0x886等。

不理解也没关系,下面我画了一张示意图,让大家直观地看一下什么是指针:

注:图中的0x886等都是为方便说明假定的虚拟地址。

我们都知道,变量的存储是需要占用内存空间的。
图中,Age是一个变量,它的存放地址是0x886,存放的值是18。
pAge是一个指针,也可以说是一个特殊的变量。它的存放地址是0x601,存放的内容是0x886。

对比,很容易发现,指针和变量有很多相似之处;不同之处在于,指针存放的是内存地址。

再仔细观察一下,可以发现:指针pAge中存储的地址=变量Age的内存地址。因此也可以说,指针pAge是指向内存单元Age的特殊变量。

相信说到这里,大家对指针已经有一个直观地认识了。那么我们如何去使用它呢?
掌握下面四个部分,大家就可以轻松上手指针了:

  1. 声明指针
  2. 使用 & 获取变量地址
  3. 使用指针存储地址
  4. 使用 * 访问指向的数据

下面我们就来分别学习这四个部分吧!

(1) 声明指针

指针作为一种特殊变量,也是需要声明的。我们先回忆下,之前在【C++养成计划】深入浅出——变量作用域(Day3)中,我们是如何声明一个int类型变量的:

int Age; //声明一个变量Age

在声明指针时,也需要指明类型。而该类型,比如int,对应的是该指针指向内存单元中存储的数的类型。

int *pAge; //声明一个指针变量

在声明变量时,我们一般会将变量初始化为0。同样,在声明指针时,我们也不希望它指向随机的内存单元。因此会将指针初始化为NULL。

int Age = 0;
int *pAge = NULL;

注:初始化为NULL的指针被称为NULL指针或空指针,空指针(即pAge)是一个定义在标准库中的值为零的常量。

(2) 使用 & 获取变量地址

符号 & 被称为引用运算符。如果Age表示一个变量,&Age将是存储该变量的内存地址。
下面,我们举一个简单的例子,来获取变量Age的地址:

#include<iostream>
using namespace std;
int main()
{int Age=18;cout<<"变量Age存放在内存中的地址是:"<<hex<<&Age<<endl;return 0;
}

运行后输出结果:

注:程序中的hex,是为了输出的格式为16进制,这是地址表示的一种约定。

(3) 使用指针存储地址

我们知道了指针是用于存储内存地址的变量,也知道了如何声明指针以及获取变量的地址。现在就可以将它们关联起来,使用指针来存储 & 获取的地址。

如上图所示,这次我们就可直接通过&Age获取地址,将其传给指针pAge。
下面举一个小例子,来声明和初始化指针。

#include<iostream>
using namespace std;
int main()
{int Age = 18;cout<<"变量Age存放在内存中的地址是:"<<hex<<&Age<<endl;int *pAge = &Age;cout<<"指针pAge中存放的地址是:"<<hex<<pAge<<endl;return 0;
}

运行结果:

可见,变量Age存放在内存中的地址=指针pAge中存放的地址。说明引用运算符 & 取到了Age的内存地址,并传给了指针pAge。

(4) 使用 * 访问指向的数据

符号 * 也被称为解除引用运算符。通常,只要是合法的指针pAge,我们就可以通过 *pAge 访问指针pAge包含的地址处存储的值。(注意是访问地址所对应的值,而不是地址)
下面,举一个简单的例子:

#include<iostream>
using namespace std;
int main()
{int Age = 18;cout<<"Age = "<<Age<<endl;int *pAge = &Age;cout<<"*pAge = "<<*pAge<<endl; return 0;
}

运行结果:

简单来说,指针pAge是指向变量Age对应的内存单元的,所以通过符号 * 就可以获得Age对应的值。


这里是一段防爬虫文本,请读者忽略。 本文原创首发于 CSDN,作者【AI 菌】。
博客首页:https://blog.csdn.net/wjinjie
本文链接:https://ai-wx.blog.csdn.net/article/details/107509243
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!


2. 动态内存分配

为了帮助开发者更好地管理应用程序占用的内存,C++提供了两个运算符:new和delete。指针是包含内存地址的变量,在高效分配内存方面扮演了重要的角色。

(1) new/delete动态分配和释放内存

当你使用new来分配内存块时,如果成功,new将返回指向一个指针,指向一个分配的内存,否则将引发异常。
使用new为一个int类型的数分配内存:

int *pNum = new int;

使用new为多个元素分配内存:

int *pNums = new int[10];

注:new请求分配内存时,并不能保证请求总能得到满足,因为这取决于系统的状态以及内存资源的可用性。

使用new分配的内存最终都需要使用对应的delete进行释放:

  1. 对于一个元素的情况:
int *pNum = new int;  //分配内存空间
-----程序块-----
delete pNum;  //释放内存空间
  1. 多个元素的情况
int *pNums = new int[10];  //分配内存空间
-----程序块-----
delete[] pNUms;  //释放内存空间

注:不再使用分配的内存后,一定要通过delete释放,否则可能出现内存泄漏。

下面举一个简单的例子:开辟一个内存空间来存放年龄,在输出存储年龄的内存地址后,再释放分配的内存空间。

#include<iostream>
using namespace std;
int main()
{int *pAge = new int;cout<<"请输入您的年龄:";cin>>*pAge;cout<<"存储年龄的内存地址是:"<<hex<<pAge<<endl;delete pAge;return 0;
}

运行结果:

(2) 带关键字const的指针

在前面【C++养成计划】深入浅出——变量作用域(Day3)中讲过,将变量声明为const时,变量的取值在整个生命周期内固定为初始值。这种变量的值是不能修改的。
指针也是变量,因此也可以将const用于指针。const指针有以下三种:

  1. 指针指向的数据为常量,不能修改。但可以修改指针包含的地址,即指针可以指向其他地方。
1.指针指向的数据为常量
int Age = 18;
const int *pAge = &Age;  //不能更改pAge指向的数据Age的值2. 想将Age改为20,错误的做法
*pAge = 20;  //错误3. 正确的做法
int CopyAge = 20;
pAge = &CopyAge; //可改变指针指向的地址
  1. 指针包含的地址是常量,不能修改,单可修改指针指向的数据。
int Age = 18;
int* const pAge = &Age;
*pAge = 20; //做法正确,可以改变值
  1. 指针包含的地址以及他指向的值都是常量,因此都不能修改。
int Age = 18;
const int* const pAge = &Age;

(3) 指针 VS 数组

当我们声明一个数组时,比如下面这样:

int Array[10];

编译器将分配固定的内存,用于存储10个整数。同时向你提供一个指向数组中第一个元素的指针。换句话说,Array是一个指针,指向第一个元素Array[0]。下面程序演示了这种关系:

#include<iostream>
using namespace std;
int main()
{int Array[10]={0,1,2,3,4,5,6,7,8,9};int *pNum = Array;cout<<"*pNum = "<<*pNum<<endl;cout<<"Array[0] = "<<Array[0]<<endl; return 0;
}

运行结果:

由此可见,数组名是一个指针,且指向第一个元素。

3. 使用指针时的常见错误

(1) 内存泄漏

如果在使用new动态分配的内存不再需要后,开发者没有及时使用delete释放内存的话,这些内存就会被预留并分配给你的应用程序。这将减少可供其他应用程序使用的系统内存量,甚至会降低应用程序的执行速度,这就是所说的内存泄漏
比如下面这样:

int* pNums = new int[10];
-----程序块-----
//忘记进行delete[]

忘记对已经请求分配的内存进行delete,很容易造成内存泄漏,我们在使用new请求分配动态内存时,一定要注意这个。

(2) 无效指针

使用运算符 * 对指针解除引用,以访问指向的值时。务必确保该指针指向了有效的内存单元,否则程序很可能崩溃。
导致指针无效的原因很多,但都要归结于糟糕的内存管理。这里仅介绍两种常见的引起指针无效的情形:

  1. 声明指针过程中,没有将其初始化为NULL,并且在后面也没有对指针赋以有效的地址。
  2. 使用new为指针申请动态内存时,当内存需要量特别大时,可能分配不成功,导致无效指针。比如下面这样:
int* pNums = new int[10000000000]; //申请的内存量太大,可能导致分配不成功

由于水平有限,博客中难免会有一些错误,有纰漏之处恳请各位大佬不吝赐教!


推荐文章

  • 【C++21天养成计划】不聊学习只谈干货(Day1)
  • 【人生苦短,我学 Python】序言——不学点Python你就out了?
  • TF2.0深度学习实战(一):分类问题之手写数字识别

面试官:指针都不会,我们不需要你这样的人!相关推荐

  1. 那些面试官,都是如何把候选人聊崩溃的

    <兄弟,你太用力了>分享了面试官关注的一些点,帮助候选人规避面试过程中的一些坑. 今天,站在候选人的角度,聊聊面试,看能否帮助面试官规避面试过程中的一些坑. 画外音:探测候选人深浅,也是一 ...

  2. 关于逻辑回归,面试官们都怎么问

    作者 | WEIWEI   整理 | NewBeeNLP 「面试官们都怎么问」系列文章主旨是尽可能完整全面地整理ML/DL/NLP相关知识点,不管是刚入门的新手.准备面试的同学或是温故知新的前辈,我们 ...

  3. 关于Transformer,面试官们都怎么问?

    作者 | Adherer 编辑 | NewBeeNLP 面试锦囊之知识整理系列,持续更新中 已发表: 关于ELMo,面试官们都怎么问 写在前面 前些时间,赶完论文,开始对 Transformer.GP ...

  4. golang实现的布隆过滤器_面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

    关注过 @Python大星 的小伙伴应该知道,2020 年 4 月 Python 小星最近裸面了阿里巴巴菜鸟网络科技有限公司. 一面中面试官非常重视解决 Redis 缓存穿透问题的利器--布隆过滤器, ...

  5. springboot 手动提交事务_面试官你都工作3年了,也做过5个项目了,怎么连事务机制都不会...

    分享职场生活.职场攻略.程序员创业资源,为一线开发者提供优质内容 张工是一名java程序员,最近到某互联网公司面试,面试官问了这样一个问题: 有这样一个场景,需要往订单主表和明细表插入数据,如何保证订 ...

  6. 关于SVM,面试官们都怎么问

    作者 | WEIWEI  整理 | NewBeeNLP 公式较多,希望大家耐心慢慢理清楚  写在前面 持续准备面试中...准备的过程中,慢慢发现,如果死记硬背的话很难,可当推导一遍并且细细研究里面的缘 ...

  7. 关于ELMo,面试官们都怎么问

    作者 | Adherer 编辑 | NewBeeNLP 面试锦囊之知识整理系列,持续更新中 写在前面 以下是关于ELMo的若干问题整理记录,自己在网上找了一些问题,对每个问题收集了一些资料,并做了整理 ...

  8. 面试官:CAP都搞不清楚,别跟我说你懂微服务!

    CAP理论指在一个分布式系统中,一致性(Consistency).可用性(Availability)和分区容错性(Partition tolerance)这三个要素最多只能同时实现两点,不可能三者兼顾 ...

  9. 关于BERT,面试官们都怎么问

    作者 | Adherer 整理 | NewBeeNLP 1.BERT 的基本原理是什么? BERT 来自 Google 的论文Pre-training of Deep Bidirectional Tr ...

  10. 关于逻辑回归,面试官都怎么问

    作者 | Chilia 整理 | NewBeeNLP 最近准备开始如同考研一般的秋招复习了!感觉要复习的东西真的是浩如烟海;) 有2023届做算法的同学可以加入我们一起复习~ 关于BERT,面试官们都 ...

最新文章

  1. 协同办公工具解决了什么问题?
  2. 单电源运算放大器全波整流电路_几种二极管整流电路原理图解。
  3. Jenkins构建之常用的触发器和Git Hook自动构建
  4. CnetOS中开关网络服务
  5. ABAP SOAMANAGER暴露的函数function module,以web service方式执行的运行时细节
  6. java开发安全问题_Java 安全开发需要了解什么?
  7. PHP报不存在图像文件,使用TP3.2.3图片文件上传显示不存在图像文件
  8. 赚小钱,靠学一门技术没问题,那想赚大钱该怎么做呢?
  9. Eclipse下maven使用嵌入式(Embedded)Neo4j创建Hello World项目
  10. TechEd2011分享
  11. 数据结构严蔚敏清华大学pdf_2019年清华大学软件学院软件工程考研经验分享
  12. 资深java面试题及答案整理(一)
  13. (转)三维GIS软件十九重唱
  14. 巧用立体声codec CL1026 的EQ
  15. java 外部输入数据 语句_在编写Java应用程序时,如需从键盘输入各种类型的多个数据,则必须在程序的开头写上( )语句。...
  16. linux系统触摸板双击,linux下Synaptics触摸板设置双指触摸
  17. 朋友入职中软一个月(外包华为)就离职了
  18. 【Linux】实用文件指令
  19. crontab 每5秒钟执行一次
  20. 扫雷游戏9*9(详细到具体每一步)

热门文章

  1. js删除字符串最后一个字符方法总汇
  2. PYTHON游戏脚本无法正常运行常见问题解决方案
  3. python自动游戏脚本_[python游戏脚本]我想用Python写一个游戏脚本,自动点击排队!...
  4. c语言和python中的数据储存方式
  5. WEBshell与文件上传漏洞
  6. 中山大学计算机学院运动会,奔跑吧!中大人!直击中山大学2020年运动会精彩瞬间...
  7. 前端报502 bad gateway的原因及解决方案
  8. Newbing注册申请使用资格
  9. ASP.NET的URL解密
  10. 辗转相除法原理的图形化