)
目录1. 内存和地址2. 指针变量和地址3. 指针变量类型的意义4. 指针运算前言指针是 C 语言中最重要也最让初学者头疼的概念之一。本文将从「内存与地址」讲起逐步带你理解指针变量、指针类型、指针运算等核心知识帮助你建立对指针的直观认识为后续深入学习打下坚实基础。本文适合C 语言初学者阅读建议你已掌握基本的变量、数据类型和数组知识。阅读本文前请确保你了解变量的创建与赋值、基本数据类型如 int、char、数组的基本使用。1.内存和地址1.内存内存作为电脑中很重要的一部分当程序运行起来时程序要加载到内存中数据的存储也是在内存中。我们先了解一下计算机中常见的单位Byte表示字节bit表示比特位我们知道当电脑中的CPU处理数据时会从内存中读取数据处理完后的数据放回内存中那么内存是如何做到有效管理的呢我们将学生宿舍与内存结合进行说明一栋学生宿舍里包含很多个房间而内存也被划分为一个个内存单元一个房间有8个床位而一个内存单元就是一个字节一个字节包含8个bit位每个房间都有对应的宿舍号通过宿舍号可以找到正确的宿舍而一个内存单元也有对应的编号通过编号可以找到对应的内存单元。宿舍号是宿舍的地址那么编号就是一个内存单元的地址。通过以上类比我们得出1个结论内存单元的编号地址指针C语言规定2.如何理解编址对于计算机中CPU和内存的联系我们给上一张关系图读取数据控制总线发出read的信号–CPU–想要访问内存空间的地址–地址总线–找到对应内存空间–读取数据–数据总线–CPUCPU和内存通过3种功能的线联系起来进行数据的传输。在今天我们主要关心一组线地址总线CPU想要访问内存中的某块空间首先要知道内存存放的地址才能去访问而每个内存单元的地址不需要存起来因为在计算机中内存的地址是通过硬件设计编写的类似钢琴每个琴键都有对应的固定发音。地址总线在32位环境下有32根地址总线1根线有2种状态0或11根线可以表示2种含义那么32根线可以表示2^32种含义每一种含义对应一个地址。2.指针变量和地址1.取地址操作符我们既然讲到编址的内容顺便提问一下变量创建的本质是什么答案是在内存中申请一块空间用来存放数据举例变量a的创建数据类型是int向内存申请一块4个字节的空间用来存放10在编译器和计算机看来a其实是对应那块空间的地址而空间的名字叫做a实际上是方便程序员自己看的。为了得到a的地址我们需要运用到取地址操作符得到的是a所占4个字节中第1个字节的地址通过这个地址顺藤摸瓜就可以知道其他字节的地址。2.指针变量和解引用操作符*1.指针变量专门用来存放地址指针的变量就叫做“指针变量”。2.如何拆解指针类型根据上面的代码为什么指针变量pa的类型是int *解释星号表示pa是一个指针变量int表示p所指向的对象的类型是整型其他类型指针变量依次类推。3.解引用操作符(*)当我们想要使用地址时此时我们要用到解引用操作符*这里的星号跟上面的星号表示指针变量的不一样这里表示通过pa里面的地址找到它所指向的对象。比如下面的例子*pa通过解引用根据pa里面的地址找到所指向的对象是变量a将0赋给变量a此时a的值变为0。到此我们又学习了一种修改数值的方法了。3.指针变量的大小在上述代码中我们创建了指针变量pa为此我们得向内存申请空间。但是pa这个指针变量的大小是多少又要向内存申请多少空间呢指针变量的大小与地址的存储需要多大空间有关。在上面编址部分我们讲到地址总线而地址总线的数量跟环境有关在32位机器下把32根地址线产生的2进制序列当做一个地址一个地址就是32个bit位需要4个字节存储指针变量的大小也就是4个字节以此类推64位机器下64根地址线做一个地址一个地址就是64个bit位需要8个字节存储指针变量的大小也就是8个字节。指针变量的大小和类型是无关的不同指针类型的变量在相同的平台下大小都是一样的。在VS2022编译器进行演示在x64环境下运行的结果在x86环境下运行的结果3.指针变量类型的意义从上述代码运行结果来看在相同环境下指针变量的大小相同那为什么还要有不同的指针类型呢下面对指针变量类型的意义进行讲解。1.指针的解引用对于上面2段代码我们通过调试观察内存的变化代码1会将a的4个字节都变成0而代码2会将a的1个字节变成0。结论指针的类型可以决定在解引用过程中的权限也就是一次可以访问并操作多少个字节数。2.指针±整数当指针加上或减去一个整数不同的指针变量类型会对结果产生什么影响呢举下面一段代码为例首先取出a的地址赋给不同类型的指针变量紧接着打印pa、pb还未发生改变前这2个地址打印出来肯定是一样的但是当pa1、pb1后地址会怎么变化呢我们从运行结果可知pa到pa1地址增加了1这说明了char类型的指针变量加1后会跳过1个字节pb到pb1地址增加了4这说明了int类型的指针变量加1后会跳过4个字节。结论指针的类型决定了指针地址向前或向后一步可以走多少字节3.void*指针在指针类型中存在着1种类型void*类型它可以接受任意类型地址但不能直接进行指针的±整数和解引用运算。举例将一个int类型变量的地址赋给int类型的指针变量这不会出现什么问题但将一个int类型变量的地址赋给char类型的指针变量,编译器就会警告了如下图然而void的出现则不会出现不兼容问题不同类型变量的地址赋给void*类型它都能够去接收。但是void*类型的指针无法参与指针相关的运算如下面代码那么void类型的指针有什么用呢一般void类型的指针用在函数参数的部分用于接受任何类型数据的地址。4.指针运算1.指针±整数例1.数组在内存中连续存放我们只要知道第一个元素的地址就可以顺藤摸瓜地找到其他元素。在之前我们对数组的打印也许是单纯的通过数组下标进行打印的但在今天我们学习了指针的一些基本知识之后我们也许可以试着用解引用来做或例子2.我们之前学过如何统计字符串的长度用strlen函数去统计。我们通过一个函数结合指针去写一下strlen函数的实现过程2.指针-指针3.指针的关系运算用指针去打印数组代码如下总结本文围绕 C 语言中的指针展开核心要点如下地址与指针内存单元都有编号这个编号就是地址C 语言规定地址即指针。通过取地址操作符可以获取变量的地址。指针变量专门用来存放地址的变量称为指针变量其类型由「指向对象的类型 *」构成如int *pa表示pa是指向整型的指针变量。解引用操作符*通过指针变量中存放的地址找到并访问它所指向的对象从而实现对数据的间接修改。指针变量的大小指针变量的大小与类型无关只与平台相关——32 位环境下为 4 字节64 位环境下为 8 字节。指针类型的意义指针类型决定了解引用时一次能访问的字节数也决定了指针/-整数时一次跳过的字节数。void*指针可以接收任意类型的地址但不能直接参与指针的加减和解引用运算常用于函数参数以接收任意类型数据的地址。指针运算指针可以/-整数实现数组元素的遍历两个指针相减可以得到元素个数指针之间还可以进行关系运算比较大小。掌握这些基础你就已经迈出了理解 C 语言指针的第一步后续可以进一步学习指针与数组、指针与函数、动态内存分配等进阶内容。