编程语言应用

首页 » 常识 » 预防 » 为什么指针被誉为C语言灵魂CSDN
TUhjnbcbe - 2023/7/28 21:43:00

作者

编程指北

来源

编程指北(id:cs_dev)

这一篇的文章主题是「指针与内存模型」

说到指针,就不可能脱离开内存,学会指针的人分为两种,一种是不了解内存模型,另外一种则是了解。

不了解的对指针的理解就停留在“指针就是变量的地址”这句话,会比较害怕使用指针,特别是各种高级操作。

而了解内存模型的则可以把指针用得炉火纯青,各种byte随意操作,让人直呼。

这篇看完,相信你会对指针有一个新的认识,坐等打脸

内存本质

编程的本质其实就是操控数据,数据存放在内存中。

因此,如果能更好地理解内存的模型,以及C如何管理内存,就能对程序的工作原理洞若观火,从而使编程能力更上一层楼。

大家真的别认为这是空话,我大一整年都不敢用C写上千行的程序也很抗拒写C。

因为一旦上千行,经常出现各种莫名其妙的内存错误,一不小心就发生了coredump......而且还无从排查,分析不出原因。

相比之下,那时候最喜欢Java,在Java里随便怎么写都不会发生类似的异常,顶多偶尔来个NullPointerException,也是比较好排查的。

直到后来对内存和指针有了更加深刻的认识,才慢慢会用C写上千行的项目,也很少会再有内存问题了。

「指针存储的是变量的内存地址」这句话应该任何讲C语言的书都会提到吧。

所以,要想彻底理解指针,首先要理解C语言中变量的存储本质,也就是内存。

1.1内存编址

计算机的内存是一块用于存储数据的空间,由一系列连续的存储单元组成,就像下面这样:

每一个单元格都表示1个Bit,一个bit在EE专业的同学看来就是高低电位,而在CS同学看来就是0、1两种状态。

由于1个bit只能表示两个状态,所以大佬们规定8个bit为一组,命名为byte。

并且将byte作为内存寻址的最小单元,也就是给每个byte一个编号,这个编号就叫内存的地址。

这就相当于,我们给小区里的每个单元、每个住户都分配一个门牌号:、、、、......

在生活中,我们需要保证门牌号唯一,这样就能通过门牌号很精准的定位到一家人。

同样,在计算机中,我们也要保证给每一个byte的编号都是唯一的,这样才能够保证每个编号都能访问到唯一确定的byte。

1.2内存地址空间

上面我们说给内存中每个byte唯一的编号,那么这个编号的范围就决定了计算机可寻址内存的范围。

所有编号连起来就叫做内存的地址空间,这和大家平时常说的电脑是32位还是64位有关。

早期Intel、的CPU就是只支持16位地址空间,寄存器和地址总线都是16位,这意味着最多对2^16=64Kb的内存编号寻址。

这点内存空间显然不够用,后来,在的基础上将地址总线和地址寄存器扩展到了20位,也被叫做A20地址总线。

当时在写minios的时候,还需要通过BIOS中断去启动A20地址总线的开关。

但是,现在的计算机一般都是32位起步了,32位意味着可寻址的内存范围是2^32byte=4GB。

所以,如果你的电脑是32位的,那么你装超过4G的内存条也是无法充分利用起来的。

好了,这就是内存和内存编址。

1.3变量的本质

有了内存,接下来我们需要考虑,int、double这些变量是如何存储在0、1单元格的。

在C语言中我们会这样定义变量:

1inta=;2charc=c;

当你写下一个变量定义的时候,实际上是向内存申请了一块空间来存放你的变量。

我们都知道int类型占4个字节,并且在计算机中数字都是用补码(不了解补码的记得去百度)表示的。

换算成补码就是:

这里有4个byte,所以需要四个单元格来存储:

有没有注意到,我们把高位的字节放在了低地址的地方。

那能不能反过来呢?

当然,这就引出了大端和小端。

像上面这种将高位字节放在内存低地址的方式叫做大端

反之,将低位字节放在内存低地址的方式就叫做小端:

上面只说明了int型的变量如何存储在内存,而float、char等类型实际上也是一样的,都需要先转换为补码。

对于多字节的变量类型,还需要按照大端或者小端的格式,依次将字节写入到内存单元。

记住上面这两张图,这就是编程语言中所有变量的在内存中的样子,不管是int、char、指针、数组、结构体、对象...都是这样放在内存的。

指针是什么东西?

2.1变量放在哪?

上面我说,定义一个变量实际就是向计算机申请了一块内存来存放。

那如果我们要想知道变量到底放在哪了呢?

可以通过运算符来取得变量实际的地址,这个值就是变量所占内存块的起始地址。

(PS:实际上这个地址是虚拟地址,并不是真正物理内存上的地址

我们可以把这个地址打印出来:

1printf(%x,a);

大概会是像这样的一串数字:0x7ffcad3b8f3c

2.2指针本质

上面说,我们可以通过符号获取变量的内存地址,那获取之后如何来表示这是一个地址,而不是一个普通的值呢?

也就是在C语言中如何表示地址这个概念呢?

对,就是指针,你可以这样:

1int*pa=a;

pa中存储的就是变量a的地址,也叫做指向a的指针。

在这里我想谈几个看起来有点无聊的话题:

为什么我们需要指针?直接用变量名不行吗?

当然可以,但是变量名是有局限的。

变量名的本质是什么?

是变量地址的符号化,变量是为了让我们编程时更加方便,对人友好,可计算机可不认识什么变量a,它只知道地址和指令。

所以当你去查看C语言编译后的汇编代码,就会发现变量名消失了,取而代之的是一串串抽象的地址。

你可以认为,编译器会自动维护一个映射,将我们程序中的变量名转换为变量所对应的地址,然后再对这个地址去进行读写。

也就是有这样一个映射表存在,将变量名自动转化为

1
查看完整版本: 为什么指针被誉为C语言灵魂CSDN