展开菜单
首页 精品内容 本月促销 装机必备 Windows macOS软件 IOS软件 Android AI PDF教程 专题
全部分类

当前位置:

首页 > 硬件相关 > 初识指针:我的学习笔记

初识指针:我的学习笔记

前言:谈及指针,大部分人只有一个感觉:太难学了,好抽象啊!但是,请不要着急,今天当你看完这一篇后,相信你肯定能够理解什么是指针了。1、内存和地址1.1理解内存和地址在介绍指针前,我们需要先了解什么是内存和地址。关于内存和地址,生活中有一个例子可以很好的解释它们比如说你住在一栋宿舍楼,大楼内有100个房间,但是房间并没有编号。这时,你的一个朋友来找你玩,如果想找到你,就得一个房间一个房间的寻找,这样效率很低。但是,如果我根据楼层和楼层的房间的情况,给每一个房间都编上号,比如:当有了门牌号,这时候你只需要将

前言:

谈及指针,大部分人只有一个感觉:太难学了,好抽象啊!但是,请不要着急,今天当你看完这一篇后,相信你肯定能够理解什么是指针了。

1、内存和地址1.1 理解内存和地址

在介绍指针前,我们需要先了解什么是内存和地址。

关于内存和地址,生活中有一个例子可以很好的解释它们

比如说你住在一栋宿舍楼,大楼内有100个房间,但是房间并没有编号。这时,你的一个朋友来找你玩,如果想找到你,就得一个房间一个房间的寻找,这样效率很低。但是,如果我根据楼层和楼层的房间的情况,给每一个房间都编上号,比如:

当有了门牌号,这时候你只需要将门牌号告诉你朋友,他就可以很快速的找到房间,找到房间里的你。

如何将上面的例子抽象到计算机里呢?你可以理解宿舍楼就是内存,房间就是内存中的一个内存单元,房间里的你就是数据,而门牌号就是地址。

所以内存就是存储数据的空间

我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们买电脑的时候,电脑上内存是8GB/16GB/32GB等,那这些内存空间如何高效的管理呢?

cpu从内存中读取数据,就好比是你朋友要在宿舍楼里找到你,而你朋友找你,也只是在一个个房间寻找。大楼里的一个一个房间的划分,让人们对大楼内的面积能够充分利用,而计算机中也是如此。内存的空间只有8GB/16GB/32GB,因此对于内存的合理运用也变的很重要。

计算机中把内存也划分为一个个的内存单元,每个内存单元的大小取1字节。

(补充)计算机中常见的单位:

一个bit可以存储一个2进制位的1和0

地址(门牌号)

内存(大楼)

其中,每个内存单元,相当于⼀个学⽣宿舍,一 个字节空间里面能放8个比特位,就好比同学们住 的八⼈间,每个人是⼀个比特位。

0xFFFFFFFF(16进制)

1个字节

0xFFFFFFFE

1个字节

1个字节

每个内存单元也都有⼀个编号(这个编号就相当 于宿舍房间的门牌号),有了这个内存单元的编 号,CPU就可以快速找到⼀个内存空间。

(内存单元)

生活中我们把门牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址,C语言中给地址起了新的名字叫:指针

1个字节

0x00000001

1个字节

0x00000000

1个字节

所以我们可以理解为:内存单元的编号 == 地址 == 指针

1.2 理解编址

生活中关于我们可以看到通过宿舍门上的门牌号,直接找到我们想去的地方。门牌号是真实存在与宿舍门上的。而内存中的地址我们该怎么理解呢?

计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。

这就像钢琴,吉他上面没有刻上“剁、来、咪、发、 唆、拉、西”这样的信息,但演奏者照样能够准 确找到每⼀个琴弦的每⼀个位置,这是为何?因为制造商已经在乐器硬件层面上设计好了,并且 所有的演奏者都知道。本质是⼀种约定出来的共识!

有点抽象,举个例子:

图书馆里有一排排的书架,每个书架又有一层层的格子,这些格子就好比内存中的存储单元。

给每个格子编上号,也就是编址,就像是要给图书馆里的每个格子都贴上标签。

那这个标签是怎么贴上去的呢?这就得靠图书馆的“硬件设计”了。

比如说,书架的排列方式、格子的划分规则,就像是硬件的设计。

想象一下,书架是固定的,它们的位置和大小决定了格子的位置和数量,这就好比硬件决定了内存有多少个可以存储数据的地方。

然后,有一套专门的标记系统,就像特殊的机器或者装置,按照书架和格子的排列,给每个格子都印上编号,这就是通过硬件实现了编址。

C:初识指针—学习笔记

那硬件设计又是怎么实现的呢?

首先,必须理解,计算机内是有很多的硬件单元,而硬件单元是要互相协同工作的。所谓的协 同,至少相互之间要能够进⾏数据传递。 但是硬件与硬件之间是互相独立的,那么如何通信呢?答案很简单,用"线"连起来。 ⽽CPU和内存之间也是有大量的数据交互的,所以,两者必须也用线连起来。通过地址总线,我们就可以了解什么是硬件编址了。

32位机器有32根地址总线, 每根线只有两态,表示0,1【电脉冲有无】,那么⼀根线,就能表示2种含义,2根线就表示4种含义,依次类推。32根地址线,就能表示2^32种含义,每⼀种含义都代表⼀个地址。 地址信息被下达给内存,在内存上,就可以找到 该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。

内存编址这件事,是靠计算机里面那些实实在在的硬件设备,按照一定的规则和办法来做好的。

简单来说,计算机的编址是通过硬件设计把每一个内存单元的地址都固定好了,不需要把地址额外的存起来。

知识补充:

32位机器有32根地址总线,64位机器有64根地址总线。 地址总线是实际存在的物理电线2、指针变量和地址

当我们了解了内存和地址的关系后,就可以开始对指针的学习啦!

在C语言中变量创建的本质是向内存申请空间

比如说:int a = 10;

这串代码就相当于向内存内申请了4个字节,一个整型占4个字节,这串空间我们想存放的数据便是变量10。

2.1 取地址操作符:&代码语言:javascript代码运行次数:0运行复制
int main(){int a = 0x11223344;//16进制数字return 0;}

16进制0x11223344,一个16进制位可以改写为4个二进制位,因此,11223344可以改写为32个二进制位表示,刚好一个整型可以放下。

我们可以调试来看一下内存:

C:初识指针—学习笔记

打开后,输入&a 并敲下回车键,列改为一行(记得在x86环境下观察,比较方便)

C:初识指针—学习笔记
C:初识指针—学习笔记

我们可以看到44,33,22,11都各占一个字节,每一个字节都有一个地址。

我们将列数改为4列再观察

C:初识指针—学习笔记

从上面我们可以看到a确实向内存申请了4个空间。

读到这我们可能会有一个新的问题,欸,4个字节都有地址,那我们怎么知道a的地址是哪一个呢?

还记得前面调试的时候我们是怎么观察地址的吗?我们通过输入&a按下回车后出现了0x00E2FEC4,因此0x00E2FEC4便是a的地址,我们也可以发现这个地址和 44 所占字节的地址一样。

总结一下,&a取出的是a所占4个字节中地址较小的字节的地址

虽然整型变量占用4个字节,但是我们只要知道了第一个字节地址,顺藤摸瓜访问到4个字节的数据也是可行的。

代码展示一下,怎么打印地址

代码语言:javascript代码运行次数:0运行复制
int main(){int a = 0x11223344;printf("&a=%p\n", &a);return 0;}

知识补充:

&是取地址操作符,想要得到地址,就需要使用这个操作符 %p:用来打印地址的占位符

结果展示:

C:初识指针—学习笔记

和前面调试的结果不是一样,是因为在打印的时候又申请了新的空间。

2.2 指针变量

在我们之前学习的过程中,我们如果想要将一个整数存储起来,就会创建一个整型变量,比如我们想存储数字10,如下代码:

代码语言:javascript代码运行次数:0运行复制
int main(){int a = 10;return 0;}

我们通过创建了一个整型变量 a 来存储10。

那么如果我们想要将我们通过&得到的地址存储起来,有没有什么办法呢?我们可以将地址存储在指针变量中。比如我们想要存放 n 的地址

代码语言:javascript代码运行次数:0运行复制
int main(){int a = 10;int * pn = &n;return 0;}

解读:int * pn = &n;

1、pn被称为指针变量

为什么呢?

&n——n的地址——地址就是指针

pn = &n;

pn就是用来存放地址的,也可以说是用来存放指针的

指针变量就是存放指针的变量。

可以通过和整型变量来理解指针变量,

整型变量:a就是用来存放整数的。

2、int * 被称为指针类型

int a = 10; int * pn = &n;

对比就可以发现,int是整数的类型,int*是指针的类型。

2.3 如何拆解指针类型

上文说到了之指针的类型是(int *),那么我们该如何理解指针类型呢?

pn的类型是int *,我们需要分别理解

*:说明pn是指针变量int:说明pn指向的对象是int类型代码语言:javascript代码运行次数:0运行复制
char ch = 'x';

如果我们想要存放x的地址该怎么写呢?

这样我们就存放了x的地址

* 告诉我们pc是指针

char则告诉我们指针指向的对象是char类型。

2.4 解引用操作符(*)

当我们将地址保存起来后,是为了后面能够使用,那么我们该怎么使用呢?

在现实生活中,我们使用地址要找到⼀个房间,在房间里可以拿去或者存放物品。

C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这里必须学习⼀个操作符叫解引用操作符(*)。

代码语言:javascript代码运行次数:0运行复制
int main(){int n = 10;int * pn = &n;    //解引用操作符(间接访问操作符)*pn = 100;printf("%d", n);return 0;}

上述代码中的*pn就使用了解引用操作符, *pn 的意思就是通过pn中存放的地址,找到指向的空间, *pn其实就是n变量了;所以*pn=100,这个操作符是把n改成了100.

C:初识指针—学习笔记

从结果上看,n的值的确被改为了100

或许通过这个例子你会觉得指针有是什么用?如果只是想修改n的值,为什么不直接写一个n=100呢?这样不是更方便吗?

其实这里是把n的修改交给了pn来操作,这样对n的修改,就多了⼀种的途径,写代码就会更加灵活, 后期慢慢就能理解了。

其实这里有一个很好的例子能说明指针的作用,生活中,有些事情是不方便自己去做的,因此呢,就需要委托别人来代替你做,比如说一个老板想要喝奶茶,但是他不会自己顶着大太阳出去买,而是会吩咐他的秘书取帮他完成,差不多就是这样,可能有些不恰当,见谅哈!

2.5 指针变量的大小

我们知道我们创建一个整型变量int的大小是4个字节,字符变量char的大小是1个字节,那么指针变量的大小又是多少呢?

思考过程:

指针变量存放的是地址,地址的存放需要多大的空间呢?知道地址存放的空间就是指针变量的大小

也就是说指针变量的大小取决与地址的大小

通过前面的内容我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后 是1或者0,那我们把32根地址线产生的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4个字节才能存储。

如果指针变量是用来存放地址的,那么指针变的大小就得是4个字节的空间才可以。

同理64位机器,假设有64根地址线,⼀个地址就是64个二进制位组成的⼆进制序列,存储起来就需要 8个字节的空间,指针变量的大小就是8个字节。

代码语言:javascript代码运行次数:0运行复制
int main(){int n = 10;int * pn = &n;printf("%zd\n", sizeof(pn));return 0;}

在32位机器上: 可以看到打印的大小是4个字节

C:初识指针—学习笔记

在64位机器上: 可以看到打印的大小是8个字节

C:初识指针—学习笔记

那么指针类型是否会影响指针变量的大小呢?我们来测试一下

代码语言:javascript代码运行次数:0运行复制
int main(){printf("%zd\n", sizeof(int*));//整型printf("%zd\n", sizeof(char*));//字符printf("%zd\n", sizeof(short*));//短整型printf("%zd\n", sizeof(double*));//双精度浮点型return 0;}

在32位系统上结果:

C:初识指针—学习笔记

在64位系统上结果

C:初识指针—学习笔记

我们可以看到,不管指针类型是什么,都不会影响指针变量的大小,指针类型的变量大小,在相同平台下,大小都是相同的。

总结:

32位平台下地址是32个bit位,指针变量大小是4个字节 64位平台下地址是64个bit位,指针变量大小是8个字节 X64环境输出结果 注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。3、指针变量类型的意义

既然指针变量大小与指针类型无关,那么为什么还要搞指针的变量类型呢?

3.1 指针的解引用代码语言:javascript代码运行次数:0运行复制
int main(){int n = 0x11223344;int* pi = &n;*pi = 0;return 0;}

调试过程:(注意观察内存里的值)

C:初识指针—学习笔记

运行到292行时内存展示44 33 22 11

C:初识指针—学习笔记

当经过*pi = 0 之后

内存里4个字节全部变为了 0

如果我们不用int *的指针类型,改为char *的类型,结果又是如何呢?

C:初识指针—学习笔记

我们可以看到只是将n的第⼀个字节改为0。

我们可以看到int类型指针可以访问4个字节,而char类型指针只访问了1个字节。

通过对比,我们可以得到一个结论:

结论:指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。

3.2 指针+-整数代码语言:javascript代码运行次数:0运行复制
int main(){int n = 0x11223344;int* pi = &n;char* pc = &n;printf("&n = %p\n", &n);printf("pi = %p\n", pi);printf("pi+1 = %p\n", pi+1);printf("pc = %p\n", pc);printf("pc+1= %p\n", pc+1);return 0;}

结果:

C:初识指针—学习笔记

我们可以发现, char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。 这就是指针变量的类型差异带来的变化。指针+1,其实跳过1个指针指向的元素。指针可以+1,那也可以-1。

结论:指针的类型决定了指针向前或者向后走一步有多大(距离)。

4、void* 指针

void的意思是无,或者空

所以void*指针是无具体为无具体类型的指针(或者叫泛型指针),这种类型的指针可以用来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的+-整数和解引用的运算。

代码语言:javascript代码运行次数:0运行复制
int main(){int n = 10;char* pc = &n;return 0;}

在上面的代码中,将⼀个int类型的变量的地址赋值给⼀个char*类型的指针变量。编译器给出了⼀个警告(如下图),是因为类型不兼容。而是用void*类型就不会有这样的问题。

C:初识指针—学习笔记

使用void*类型的指针接收地址就不会出现警告

C:初识指针—学习笔记

void* 类型的指针不能直接进行指针的+-整数和解引用的运算

代码语言:javascript代码运行次数:0运行复制
int main(){int n = 10;void* pc = &n;*pc = 20;return 0;}

当我们想运行的时候,就会报下面这个错误

C:初识指针—学习笔记

void* 类型的指针可以接收不同类型的地址,但是无法直接进行指针运算。

这是因为void*是一个无具体类型的指针,当进行解运算的时候,没法确定访问几个字节。

既然如此,那void*有什么作用呢?

专门用来存放别人传送过来的地址,当你不知道别人给你传的是什么类型的指针的时候,就可以使用void*来存放,当需要进行解运算的时候,在使用强制类型转换来实现。

比如:

代码语言:javascript代码运行次数:0运行复制
int main(){int n = 10;void* pc = &n;*(int*)pc = 20;return 0;}

这样就将类型强制转换成了整型指针,结果就可以打印出来了

C:初识指针—学习笔记
结语:

本篇文章主要讲了指针的基本知识,通过本篇文章能够了解什么是指针,指针变量,指针类型是什么。后面会继续更新指针相关知识,希望能够帮助大家攻克指针这一模块。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
硬件相关
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

PDF教程

PDF教程适合刚接触PDF文件的用户,本文整理PDF打开、编辑、转换、合并、压缩等常见基础操作。通过这些教程可以快速了解PDF文件怎么处理,解决办公、学习和资料科整理中的常见问题。使用极轻PDF可在线完成多种PDF操作,适合新手快速上手。

Mac软件 更多
灵活计算器
灵活计算器

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

图几
图几

图几是一款适用于 macOS 的截图、标注与美化工具,支持离线操作保障隐私。界面整理和高频系统操作被放到一起考虑,桌面或窗口内容一多时,管理起来会更省心。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Menuist
Menuist

Menuist 是一款面向 macOS 的 Finder 右键菜单增强工具,主要用来补充新建文件、快捷导航等常用操作,让日常文件管理和访问路径时更高效、更顺手。

Mole
Mole

Mole 是一款专为 Mac 设计的深度清理优化工具,涵盖缓存清理、应用管理及实时状态监控等功能。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

WINDOWS 更多
Windows 10
Windows 10

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

傲梅轻松备份
傲梅轻松备份

傲梅轻松备份是一款专业易用的数据备份软件,为重要数据提供安全保障。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

Wise Folder Hider Pro
Wise Folder Hider Pro

Wise Folder Hider Pro 是一款专业级文件和文件夹隐藏加密软件,为私密数据添加多重保护。高频操作更强调就近处理,浏览、整理和跨目录移动文件时,来回切换和重复点击都会少很多。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

PinStack
PinStack

PinStack是一款轻量级的Windows平台剪贴板管理工具,优化您的剪贴板使用体验。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Seer
Seer

Seer是一款在Win平台下的空格键功能增强效率工具,只需轻敲空格键,就能预览几乎任何格式的文件。它更适合把零散的小功能集中起来使用,处理高频琐碎任务时会更省事。