当前位置:

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

初识指针:我的学习笔记

前言:谈及指针,大部分人只有一个感觉:太难学了,好抽象啊!但是,请不要着急,今天当你看完这一篇后,相信你肯定能够理解什么是指针了。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:初识指针—学习笔记
结语:

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

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
硬件相关 变量
相关文章 更多
显示器色温怎么调不刺眼?色温调多少看着最舒服
显示器色温怎么调不刺眼?色温调多少看着最舒服

详解显示器色温的舒适调节区间、刺眼的核心诱因,以及在不同使用场景与环境光下的具体调节步骤与校准方法。

显卡风扇不转怎么回事判断是否正常及解决方法
显卡风扇不转怎么回事判断是否正常及解决方法

发现显卡风扇不转先别慌,这很可能是正常的智能启停功能。本文详解如何区分待机静音与硬件故障,提供从软件检测到物理清理的完整解决思路。

笔记本加内存条后无法开机怎么办及解决方法
笔记本加内存条后无法开机怎么办及解决方法

笔记本加装新内存后遇到黑屏或无法开机?不要慌张,本文通过重新插拔、清洁金手指、单根测试等具体操作步骤,帮你快速判断是安装失误还是硬件不兼容,并给出相应解决办法。

电脑主机前置usb不能用怎么解决排查修复教程
电脑主机前置usb不能用怎么解决排查修复教程

针对电脑主机前置USB接口无法识别设备的问题,本文提供一套基于因果逻辑的排查流程。涵盖检查机箱内部USB针脚连接、验证BIOS中USB控制器状态、更新芯片组驱动以及排除供电不足等常见原因,帮助用户快速恢复接口功能。

无线鼠标充不进电解决办法及故障排查步骤
无线鼠标充不进电解决办法及故障排查步骤

遇到无线鼠标充不进电的问题,不要急于更换设备。本文详解从清理接口氧化层、更换数据线到检测电池电压的完整排查流程,帮助你判断是临时故障还是硬件损坏。

蓝牙游戏手柄连接教程吃鸡
蓝牙游戏手柄连接教程吃鸡

想知道如何用蓝牙手柄玩吃鸡游戏?本文详细讲解手机蓝牙手柄的连接步骤、主流映射软件的使用方法以及实战中的键位布局技巧,助你提升射击手感,同时解析外设玩家的匹配机制与注意事项。

游戏手柄蓝牙连接为何每次都要重连原因排查与解决方法
游戏手柄蓝牙连接为何每次都要重连原因排查与解决方法

本文深入分析游戏手柄蓝牙频繁断开且需重连的根本原因,涵盖电池电压检测、操作系统电源管理策略及驱动冲突。通过具体的系统设置调整和固件更新步骤,解决蓝牙握手失败问题,恢复手柄的稳定连接状态。

显示器画面模糊抖动怎么解决及排查方法教程
显示器画面模糊抖动怎么解决及排查方法教程

遇到显示器画面模糊或抖动时,可通过检查视频连接线、调整系统分辨率与刷新率、更新显卡驱动等步骤进行排查和修复。

小米智能门锁换电池后怎么开机
小米智能门锁换电池后怎么开机

小米智能门锁更换新电池后无法开机或屏幕不亮?本文详解电池极性检查、金属触点清洁及强制重启方法,帮你快速解决供电问题,让门锁恢复正常使用。

电视机声音怎么连接到外置音响
电视机声音怎么连接到外置音响

想让电视声音更震撼?本文详解如何通过HDMI ARC、光纤、蓝牙和3.5mm接口将电视连接至外置音响,包含具体设置步骤与常见问题排查,助你轻松打造家庭影院。

查看更多
精品专题 更多
装机必备
装机必备

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

Windows
Windows

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

PDF教程
PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
Shapr3D macOS版
Shapr3D macOS版
Mac

Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

REAPER macOS版
REAPER macOS版
Mac

REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

Ableton Live macOS版
Ableton Live macOS版
Mac

Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。

WINDOWS 更多
3dmax(3ds max)
3dmax(3ds max)
Windows

Autodesk 3ds Max 是一款专业的三维建模、动画与渲染软件,广泛应用于建筑可视化、游戏开发、影视动画、广告设计和产品展示等领域。

photoshop
photoshop
Windows、macOS 、 iPad

Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

Blender
Blender
Windows、macOS 和 Linux

Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。