0

0

深入理解指针(1)

星夢妙者

星夢妙者

发布时间:2025-04-25 12:46:01

|

357人浏览过

|

来源于php中文网

原创

1. 内存和地址

1.1 内存

在讨论内存和地址之前,让我们从生活中的一个例子开始:假设你住在一个有100个房间的宿舍楼里,但这些房间没有编号。如果你的朋友来找你玩,他必须逐个房间寻找,这样效率很低。然而,如果我们根据楼层和房间的位置为每个房间编号,那么朋友只要知道房间号就能快速找到你。

将这个例子应用到计算机中,情况又如何呢?我们知道,计算机的CPU(中央处理器)在处理数据时,需要从内存中读取数据,并将处理后的数据存回内存。我们购买电脑时,通常看到的内存容量是8GB、16GB或32GB等。那么,如何高效管理这些内存空间呢?

实际上,内存被划分为一个个内存单元,每个内存单元的大小为一个字节。

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

一个比特位可以存储一个二进制的位1或者0。

每个内存单元相当于一个学生宿舍,一个字节的空间内可以容纳8个比特位,就像宿舍里的八人间,每个人代表一个比特位。每个内存单元都有一个编号(相当于宿舍的门牌号),有了这个编号,CPU就可以快速找到特定的内存空间。

在生活中,我们把门牌号称为地址;在计算机中,内存单元的编号也被称为地址。在C语言中,地址被称为指针。

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

深入理解指针(1)

1.2 如何理解编址

CPU访问内存中的某个字节空间,必须知道这个字节空间在内存中的位置。由于内存中的字节数量庞大,因此需要对内存进行编址(就像给众多宿舍编号一样)。计算机中的编址并不是记录每个字节的地址,而是通过硬件设计完成的。

钢琴和吉他上并没有标注“剁、来、咪、发、唆、拉、西”这样的信息,但演奏者依然能准确找到每个琴弦的位置。这是为什么呢?因为制造商已经在乐器的硬件层面上设计好了,并且所有演奏者都知道这种约定。

首先,必须理解计算机内部有很多硬件单元,这些硬件单元需要协同工作。所谓的协同,至少需要能够进行数据传递。然而,硬件与硬件之间是独立的,那么如何通信呢?答案很简单,用“线”连接起来。

CPU和内存之间也有大量的数据交互,因此,两者也必须用线连接。不过,我们今天关注一组线,称为地址总线。硬件编址也是如此。我们可以简单理解,32位机器有32根地址总线,每根线只有两种状态,表示0或1(电脉冲的有无),一根线就能表示两种含义,两根线就能表示四种含义,依此类推。32根地址线就能表示2^32种含义,每种含义都代表一个地址。地址信息被下达给内存,内存就可以找到该地址对应的数据,并通过数据总线将数据传回CPU的寄存器。

  1. 指针变量和地址

2.1 取地址操作符(&)

理解了内存和地址的关系后,我们再回到C语言。在C语言中,创建变量实际上是在内存中申请空间。例如:

深入理解指针(1)深入理解指针(1)

如上所示的代码创建了一个整型变量a,内存中申请了4个字节用于存放整数10,每个字节都有地址,如图所示,4个字节的地址分别是:

深入理解指针(1)

那么我们如何得到a的地址呢?这里需要学习一个操作符(&)——取地址操作符。

深入理解指针(1)深入理解指针(1)

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

2.2 指针变量和解引用操作符(*)

2.2.1 指针变量

通过取地址操作符(&)得到的地址是一个数值,例如:0x006FFD70。这个数值有时也需要存储起来,以便后期使用。我们将这样的地址值存放在指针变量中。例如:

深入理解指针(1)

指针变量也是一种变量,这种变量用于存储地址,存放在指针变量中的值都被理解为地址。

2.2.2 如何拆解指针类型

这里pa左边写的是int是在说明pa是指针变量,而前面的int是在说明pa指向的是整型(int)类型的对象。

深入理解指针(1)

如果有一个char类型的变量ch,ch的地址应该放在什么类型的指针变量中呢?

2.2.3 解引用操作符

我们将地址保存起来,未来是要使用的,那么如何使用呢?

在现实生活中,我们使用地址找到一个房间,在房间里可以取走或存放物品。

OEmarry婚嫁电子商务系统免费版
OEmarry婚嫁电子商务系统免费版

OEmarry婚庆商家电子商务网站系统(又名:OEmarry婚嫁O2O电商平台系统)是O.E研发团队继OElove婚恋网站产品发布之后经长期的深入调研策划后,根据婚庆行业客户实际应用需求而提供的一套以满足企业级(OEPHP MVC架构)大型数据架构及大规模运营需求的解决方案,该系统的集商家展示点评、O2O团购、垂直搜索、分类导行、本地信息、优惠券、商家活动、在线购物、微信营销、广告管理、手机app

下载

C语言中也是如此,只要拿到了地址(指针),就可以通过地址(指针)找到指向的对象。这里必须学习一个操作符——解引用操作符(*)。

深入理解指针(1)

上面的代码中第7行就使用了解引用操作符,pa的意思是通过pa中存放的地址找到指向的空间,pa实际上就是a变量;所以*pa = 0,这个操作是将a改成了0。

如果目的是把a改成0,直接写成a = 0;不就行了,为什么还要使用指针呢?实际上,这里是将a的修改交给了pa来操作,这样对a的修改就多了一种途径,写代码会更加灵活,后期慢慢就能理解了。

2.3 指针变量的大小

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

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

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

深入理解指针(1)深入理解指针(1)

结论:

  • 在32位平台下,地址是32个bit位,指针变量大小是4个字节。
  • 在64位平台下,地址是64个bit位,指针变量大小是8个字节。
  • 注意,指针变量的大小与类型无关,只要是指针变量,在相同的平台下,大小都是相同的。
  1. 指针变量类型的意义

指针变量的大小与类型无关,只要是指针变量,在同一个平台下,大小都是一样的,为什么还要有各种各样的指针类型呢?

实际上,指针类型是有特殊意义的,我们接下来继续学习。

3.1 指针的解引用

对比以下两段代码,主要在调试时观察内存的变化。

深入理解指针(1)深入理解指针(1)

调试时我们可以看到,代码1会将n的4个字节全部改为0,但代码2只是将n的第一个字节改为0。

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

例如:char的指针解引用只能访问一个字节,而int的指针解引用可以访问四个字节。

3.2 指针+-整数

深入理解指针(1)

我们可以看出,char类型的指针变量+1跳过1个字节,而int类型的指针变量+1跳过了4个字节。这就是指针变量的类型差异带来的变化。指针+1实际上是跳过一个指针指向的元素。指针可以+1,也可以-1。

结论:指针的类型决定了指针向前或向后移动一步的距离。

3.3 void* 指针

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

深入理解指针(1)

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

深入理解指针(1)

使用void*类型的指针接收地址:

深入理解指针(1)

VS编译代码的结果:

深入理解指针(1)

这里我们可以看到,void*类型的指针可以接收不同类型的地址,但无法直接进行指针运算。

那么void*类型的指针有什么用呢?

一般void*类型的指针用于函数参数部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果。使得一个函数可以处理多种类型的数据,在《深入理解指针(4)》中我们会详细讲解。

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

397

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

618

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

354

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

258

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

600

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

525

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

640

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

601

2023.09.22

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

19

2026.01.20

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 2.8万人学习

Django 教程
Django 教程

共28课时 | 3.3万人学习

React 教程
React 教程

共58课时 | 3.9万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号