彻底理解C语言中的指针

 2024-02-17 04:01:26  阅读 0

来源丨转载自码农荒岛求生(ID:-it)

作者丨码农的荒岛求生

假设你的内存非常小。 这个内存只有8个字节。 没有高级语言或操作系统。 你操作的数据单位是单个字节。 你应该如何读写这段内存?

字节是数字吗_c中数字10是几个字节_字节表示的是什么

请注意这里的限制。 再读一遍。 没有高级语言,也没有操作系统。 在这样的限制下,你必须面对内存读写的本质。

这个本质是什么?

本质是你需要认识到内存是一个包含字节的小盒子,而这些小盒子的编号是从0到N。

这时,如果你想计算1+2,那么你必须先将1和2分别放入两个小盒子中。 假设我们使用Store指令将数字1放入6号小盒子中,那么指令表示是这样的:

store 1 6

请注意此说明。 这里有两个数字:1和6。虽然都是数字,但是这两个数字的含义是不同的。 一个代表数值,另一个代表内存地址。

与写作相对应的是阅读。 假设我们使用加载指令,如下所示:

load r1 6

还有一个问题。 这条指令是把数字6写入r1寄存器还是把6号小盒子里的数字写入r1寄存器?

正如您所看到的,这里的数字是不明确的。 它可以表示数值或地址。 为了区分,我们需要给号码添加一个标识符。 例如前面加$符号,则代表数值,否则为地址:

store $1 6load r1 6

这样就不会有歧义了。

现在,内存编号 6 已加载值 1:

字节表示的是什么_c中数字10是几个字节_字节是数字吗

即地址6代表数字1:

地址6 -> 数字1

但《地址6》对人类来说太不友好了。 人类更喜欢代号,即名字。 假设我们将“地址6”的名称改为a,a代表地址6,即a中存储的值。 1.人类在代数中的直观表示是:

a = 1

于是所谓的字变量就诞生了。

字节是数字吗_字节表示的是什么_c中数字10是几个字节

我们可以看到变量a表面上相当于值1,但其背后还隐藏着重要信息,即变量a代表的数字1存储在6号内存地址处,即变量a或符号 a 背后的含义是:

代表值1

该值存储在内存地址6中

第二条信息目前看来并不是很重要,所以暂时先不去关心它。

既然有变量a,就会有变量b。 如果有这样的表示:

b = a

将a的值赋给b,这个赋值在内存中应该如何表示?

这很简单。 我们还找到了一个用于变量 b 的小盒子。 假设变量b放在2号小盒子上:

字节表示的是什么_字节是数字吗_c中数字10是几个字节

可以看到,我们已经完全复制了变量a的数据。

现在我们有了变量,让我们升级它。 假设变量a不仅可以表示占用1个字节的数据,还可以表示占用任意内存量的数据,如下所示:

字节是数字吗_字节表示的是什么_c中数字10是几个字节

现在变量a占用了5个字节,占据了整个内存的一半以上。 如果我们仍然想表达 b = a 会发生什么?

如果你仍然使用复制的方式,你会发现我们的内存空间已经不够用了,因为整个内存大小只有8个字节。 使用复制方法,仅这两个变量代表的数据就会占用10个字节。

怎么做?

不要忘记变量 a 背后有两个含义。 让我们来看看:

代表值1

该值存储在内存地址6中

我们重点说一下第二个意思。 这个寓意告诉我们什么道理呢?

它告诉我们,无论一个变量占用多少内存空间,我们总能通过它在内存中的地址找到数据,而内存地址只是一个数字,与该变量占用的空间大小无关。数据。

啊哈,现在终于可以使用变量的第二个含义了。 如果我们想使用变量b也引用变量a,为什么我们必须直接复制数据的副本? 直接使用地址是不好的,像这样:

c中数字10是几个字节_字节是数字吗_字节表示的是什么

变量a在内存中的地址是3,所以我们只能将数字3存储到变量b中。

现在变量 b 开始变得非常有趣。

首先,变量b没有什么特别之处,只是变量b中存储的东西不能用数值来解释,而必须用地址来解释。

当变量不仅可以存储值还可以存储内存地址时,指针就诞生了。

有很多资料只说指针是地址,但小风哥认为这是一种偷懒的解释。 只停留在汇编层面来理解,这是有偏见的。 在高级语言中,指针首先是一个变量,但这个变量保存的只是一个地址,而指针则是内存地址的高级抽象。

如果你只把指针理解为内存地址,那么你一定知道所谓的间接寻址。

这是什么意思?

如果使用汇编语言,变量a的值怎么写?

load r1 1

想一想,是不是有问题,所以本例指令会将值3加载到r1寄存器中,但是我们要将内存地址1中保存的值解释为内存地址,必须再次为1添加标识符, 例如 @:

load r1 @1

这时,指令会先读取内存地址1中保存的值,发现是3,然后再根据内存地址解释3。 3指向的数据变成了a:

地址1 -> 地址3 -> 数据a

这就是所谓的间接寻址。 在汇编语言中,你必须意识到这一级间接寻址,因为汇编语言中没有变量的概念。

然而高级语言就不一样了。 这里有一个变量的概念。 此时地址1代表变量b。 但使用变量的一个好处是,很多情况下我们只需要关心它的第一个含义,这意味着我们只需要关心变量b。 地址 3 保存在 中,而不关心变量 b 存储在哪里。 这样,我们在使用变量b的时候,就不需要在大脑中去思考间接寻址的问题了。 在程序员的大脑中,变量b直接指向数据a:

b -> 数据a

我们再比较一下:

地址1 -> 地址3 -> 数据a   # 汇编语言层面变量b -> 数据a            # 高级语言层面

这就是为什么我说指针实际上是内存地址的更高层次的抽象。 这种抽象的目的是为了屏蔽间接寻址。

当变量不仅可以存储值还可以存储地址时,一个新的时代已经到来:看似松散的内存可以通过指针在内部进行组织,而这也使得程序可以直接处理复杂的数据结构,比如像下图这样:

这就是所谓的链表。

指针的概念首先出现在PL/I语言中。 当时是为了增加链表的处理能力。 不要以为像链表这样的数据结构很常见。 这在 1964 年左右并不是一件容易的事。你还不知道链表。 你可以参考这篇文章。

值得一提的是,操作系统是用PL/I语言实现的。 这也是第一个用高级语言实现的操作系统。 然而,该操作系统在商业上并不成功。 参与该项目的Ken后来决定自己写一个,更简单地说,Unix和C语言诞生了,也许是因为他们在开发过程中看到了PL/I语言中指针的威力。 C语言也有指针的概念。

1、

2、

3.

4.

5.

字节是数字吗_字节表示的是什么_c中数字10是几个字节

标签: 变量 内存 数值

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码