讲师中心 微信公众号

工具推荐

视频效率加速
updream

一键生成高质量推广成片

立刻MV
立刻MV

低成本歌曲 MV、视频生成

AniShort
AniShort

AI短剧协同制作平台

Laper
Laper

剧本策划到成片协作

C:初识指针—学习笔记

梦丽吖_7825

梦丽吖_7825

发布时间:2025-04-27 09:34:12

|

1126人浏览过

|

来源于php中文网

原创

前言:

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

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:用来打印地址的占位符

结果展示:

ImageMagick 批处理处理器
ImageMagick 批处理处理器

使用 ImageMagick 的 convert 和 mogrify 命令进行批量图像处理,支持调整大小、裁剪、水印和格式转换。与 libvips 集成以实现高性能缩略图生成。

下载
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:初识指针—学习笔记
结语:

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

热门AI工具

更多
讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

函子Zion

一款支持AI搭建、可视化编辑和多端发布的全栈无代码开发平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

更多
java进行强制类型转换
java进行强制类型转换

强制类型转换是Java中的一种重要机制,用于将一个数据类型转换为另一个数据类型。想了解更多强制类型转换的相关内容,可以阅读本专题下面的文章。

2278

2023.12.01

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

7479

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3545

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

4688

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

3125

2025.08.29

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

636

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

391

2025.11.27

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

399

2026.04.23

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

20

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Postman环境变量管理手册
Postman环境变量管理手册

共0课时 | 0人学习

Starlette官方配置指南
Starlette官方配置指南

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn