各位少年,大家好,我是博主那一脸阳光
,今天给大家分享C语言中的指针的基本概念,由于指针的类型比较多,所以我们采取多篇博客来解释。
前言
在探索C语言的广袤世界中,指针无疑是最具魔力与深邃的元素之一。它就像一把神秘的钥匙,解锁了数据在内存中的秘密花园;又如同一位技艺高超的向导,引领我们在复杂的数据迷宫中自由穿行。
想象一下,你置身于一个巨大的图书馆,每一本书都代表着一块内存空间,存储着特定的信息。而“指针”,便是一张写有书架编号和位置的地图,指向那些珍贵的知识宝藏。当你手握指针,就拥有了瞬间抵达任意书籍的能力,可以阅读、修改或移动这些信息。在这个类比中,改变指针所指向的位置,就好比更换了书架上的书籍;通过指针来操作内存中的数据,则类似于翻阅书本并记录新的篇章。
因此,在C语言的舞台上,掌握指针的艺术就是掌握了高效操控内存和数据的秘诀。这不仅能帮助我们更深入地理解程序运行机制,更能使代码变得更加简洁且强大。让我们一起揭开指针的神秘面纱,以全新的视角去解读这个编程世界中不可或缺的角色。
内存和地址
假设有⼀栋宿舍楼,把你放在楼⾥,楼上有100个房间,但是房间没有编号,你的⼀个朋友来找你玩,
如果想找到你,就得挨个房⼦去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给
每个房间编上号,如:
⼀楼:101,102,103…
⼆楼:201,202,203…
…
有了房间号,如果你的朋友得到房间号,就可以快速的找房间,找到你。
bit - ⽐特位 byte - 字节 KB MB GB TB PB
我们知道计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数
据也会放回内存中,那我们买电脑的时候,电脑上内存是8GB/16GB/32GB等,那这些内存空间如何⾼ 效的管理呢?
其实也是把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节。 计算机中常⻅的单位(补充): ⼀个⽐特位可以存储⼀个2进制的位1或者0
⽣活中我们把⻔牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址。C语⾔中给地址起 了新的名字叫:
指针
所以我们可以理解为:
内存单元的编号 == 地址 == 指针
CPU访问内存中的某个字节空间,必须知道这个 字节空间在内存的什么位置,⽽因为内存中字节 很多,所以需要给内存进⾏编址(就如同宿舍很
多,需要给宿舍编号⼀样)。 计算机中的编址,并不是把每个字节的地址记录 下来,⽽是通过硬件设计完成的。 钢琴、吉他
上⾯没有写上“都瑞咪发嗦啦”这样 的信息,但演奏者照样能够准确找到每⼀个琴弦 的每⼀个位置,这是为何?因为制造商已经在乐
器硬件层⾯上设计好了,并且所有的演奏者都知 道。本质是⼀种约定出来的共识! 硬件编址也是如此。 ⾸先,必须理解,计算机内是有很多的硬件单
元,⽽硬件单元是要互相协同⼯作的。所谓的协 同,⾄少相互之间要能够进⾏数据传递。 但是硬件与硬件之间是互相独⽴的,那么如何通
信呢?答案很简单,⽤"线"连起来。 ⽽CPU和内存之间也是有⼤量的数据交互的,所 以,两者必须也⽤线连起来。
不过,我们今天关⼼⼀组线,叫做地址总线。 我们可以简单理解,32位机器有32根地址总线, 每根线只有两态,表⽰0,1【电脉冲有⽆】,那么
⼀根线,就能表⽰2种含义,2根线就能表⽰4种含 义,依次类推。32根地址线,就能表⽰2^32种含 义,每⼀种含义都代表⼀个地址。
地址信息被下达给内存,在内存上,就可以找到 该地址对应的数据,将数据在通过数据总线传⼊ CPU内寄存器。
总结
内存被划分为一个个的单元,一个内存单元的大小就是一个字节。 每个内存单元都给一个编号,这个编号就是地址,C语言中把地址又称为:指针 编号==地址==指针
指针变量和地址
取地址操作符(&)
理解了内存和地址的关系,我们再回到C语言,在C语言中创建变量其实就是向内存申请空间,比如:
#include <stdio.h> int main() { int a = 10;//向内存中申请四个字节 return 0; }
如何获得a的地址?
很显然用取地址操作符就可以了。
#include <stdio.h> int main() { int a = 10; &a; return 0; }
这样我们就取到了a的地址,但是a的地址是什么呢?那不是我们得打印出来看看喽,看下面例子。
#include <stdio.h> int main() { int a = 10; printf("%p\n",&a);//%p打印地址操作符 return 0; }
输入的结果是16进制的输出方式,一个16进制位就是4个二进制。把上面每个代码转换为二进制以后,就是在计算机内存储的地址(计算机存储的是二进制,打印的是16进制地址)。
指针变量和解引⽤操作符(*)
那我们通过取地址操作符(&)拿到的地址是⼀个数值,⽐如:0x006FFD70,这个数值有时候也是需要
存储起来,⽅便后期再使⽤的,那我们把这样的地址值存放在哪⾥呢?答案是:指针变量中。
```c #include <stdio.h> int main() { int a = 10; int* pa = &a;//取出a的地址并存储到指针变量pa中 return 0; } ```指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址
我们看到pa的类型是 int* ,我们该如何理解指针的类型呢?
int a = 10;
int * pa = &a;
这⾥pa左边写的是 int* * 是在说明pa是指针变量,⽽前⾯的 int 是在说明pa指向的是整型(int)
类型的对象。
例子
那如果有⼀个char类型的变量ch,ch的地址,要放在什么类型的指针变量中呢?
char ch = 'w'; pc = &ch;//pc 的类型怎么写呢?
解引⽤操作符
我们将地址保存起来,未来是要使⽤的,那怎么使⽤呢?
在现实⽣活中,我们使⽤地址要找到⼀个房间,在房间⾥可以拿去或者存放物品。
C语⾔中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)
指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)。
#include <stdio.h> int main() { int a = 100; int* pa = &a; *pa = 0; return 0; }
上⾯代码中第7⾏就使⽤了解引⽤操作符, *pa 的意思就是通过pa中存放的地址,找到指向的空间,
pa其实就是a变量了;所以pa = 0,这个操作符是把a改成了0.
有同学肯定在想,这⾥如果⽬的就是把a改成0的话,写成 a = 0; 不就完了,为啥⾮要使⽤指针呢?
其实这⾥是把a的修改交给了pa来操作,这样对a的修改,就多了⼀种的途径,写代码就会更加灵活,
后期慢慢就能理解了。
指针变量的⼤⼩
前⾯的内容我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后
是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4
个字节才能存储。
如果指针变量是⽤来存放地址的,那么指针变的⼤⼩就得是4个字节的空间才可以。
同理64位机器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要
8个字节的空间,指针变的⼤⼩就是8个字节
#include <stdio.h> //指针变量的⼤⼩取决于地址的⼤⼩ //32位平台下地址是32个bit位(即4个字节) //64位平台下地址是64个bit位(即8个字节) int main() { printf("%zd\n", sizeof(char *)); printf("%zd\n", sizeof(short *)); printf("%zd\n", sizeof(int *)); printf("%zd\n", sizeof(double *)); return 0; }
总结
在C语言的奇幻旅程中,掌握指针运用的艺术就好比掌握了驾驭编程世界的魔法。它使我们能够以更直接、更灵活的方式触及程序运行的核心,赋予代码生命与活力。指针,这一强大的工具,不仅提升了我们对计算机底层运作机制的认知深度,也极大地拓宽了问题解决的可能性空间。
犹如那神秘的地图指引着我们在信息的海洋里游刃有余,善用指针,就如同手持一把解开内存迷局的万能钥匙,于无形之中驾驭数据流转的脉络。因此,在这场探索之旅的终点,每一位深入钻研C语言的勇者都将领略到指针所带来的无穷魅力和无尽潜力。让我们携手揭开更多未知的秘密,共同驾驭这把开启高效编程之门的“金钥匙”,在C语言的世界里书写属于我们的精彩篇章。