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

文章目录

  • 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. [LeetCode]题解(python):019-Remove Nth Node From End of List
  2. 关于开发过程中的空指针问题
  3. php/ajax/mysql
  4. 1020 月饼 (25分)
  5. CSU 1259 bfs找最短路
  6. zlib库删除后的恢复
  7. 一个计算机高手的成长zz
  8. 基于javafx+sqlserver的仓库管理系统
  9. R语言ggplot2可视化:loess回归曲线可视化、填充两条 loess回归曲线之间的区域实战(Fill region between two loess-smoothed lines)
  10. macOS 桌面应用 图标制作教程
  11. linux给文件夹腹权限,文件的权限_腹有诗书气自华的技术博客_51CTO博客
  12. 如何使用JavaScript来判断用户设备类型
  13. Android 源码分析工具
  14. KSQL DB 学习笔记1
  15. 千锋python培训班课程
  16. EXCEL操作视频集1-10
  17. ​IBM、Google、Oracle三巨头的公有云之殇(下)
  18. python tif格式的图片转换成其他格式
  19. springboot集成spring-boot-starter-data-elasticsearch
  20. ema matlab实现,用vba实现EMA函数

热门文章

  1. 哈工大计算机网络实验四——简单网络组建配置 Cisco Packet Tracer 使用指南
  2. Outlook 如何打开或关闭邮件预览功能
  3. 2022NewStarCTF pwn大部分题解
  4. 风水 第一节 环境感受简谈
  5. Linux C调用Python 函数
  6. 批量清空表数据(不删除表)
  7. 斗地主智能(AI)出牌算法
  8. 2、计算机智能的基础:算术和逻辑机械化
  9. 信创平台下NFS协议及服务配置
  10. 编译型语言和解释型语言【附 动(静)态语言 、动(静)态类型语言、强(弱)类型语言】