《程序是怎样跑起来的》读书笔记——第四章 熟练使用有棱有角的内存

1 内存的物理机制很简单

内存实际上是一种名为内存 IC 的电子元件。内存IC 中有电源、地址信号、数据信号、控制信号等用于 输入输出的大量引脚(IC 的引脚),通过为其指定地址(address),来 进行数据的读写。

那么,这个内存 IC 中能存储多少数据呢?
数据信号引脚有 D0~D7 共八个,表示一次可以输入输出 8 位(= 1 字节)的数据。
地址信号引脚有 A0~A9 共十个,表示可以指定 0000000000~1111111111 共 1024 个地址。而地址用来表示数据的存储场所,因此我们可以得出这 个内存 IC 中可以存储 1024 个 1 字节的数据。因为 1024 = 1K,所以该 内存 IC 的容量就是 1KB。

往该内存 IC 中写入 1 字节的数据。
为了实现该目的,可以给 VCC 接入+5V,给 GND 接入 0V 的电源,并使用 A0~A9 的地址信号来 指定数据的存储场所,然后再把数据的值输入给 D0~D7 的数据信号, 并把 WR(write = 写入的简写)信号设定成 1。执行完这些操作,就可 以在内存 IC 内部写入数据(图 4-2 (a))了。

读出数据时,只需通过 A0~A9 的地址信号指定数据的存储场所, 然后再将 RD(read = 读出的简写)信号设成 1 即可。执行完这些操 作,指定地址中存储的数据就会被输出到 D0~D7 的数据信号引脚
(图 4-2(b))中。

总体来讲,内 存 IC 内部有大量可以存储 8 位数据的地方,通过地址指定这些场所, 之后即可进行数据的读写。

2 内存的逻辑模型是楼房

1KB 内存的模型

程序员眼里的内存模型中,还包含着物理内存中不存在的 概念,那就是数据类型。

编程语言中的 数据类型表示存储的是何种类 型的数据。从内存来看,就是占用的内存大小(占有的楼层数)的意 思。

这是一个往 a、b、c 这 3 个变量中写入数据 123 的 C 语言程序。这 3 个变量表示的 是内存的特定区域。通过使用变量,即便不指定物理地址,也可以在 程序中对内存进行读写。这是因为,在程序运行时,Windows 等操作 系统会自动决定变量的物理地址。

// 定义变量 
char a; //表示 1 字节长度的 char
short b; //表示 2 字节长度的 short
long c;//以及表示 4 字节长度的 long
// 给变量赋值 
a = 123;
b = 123;
c = 123;

3 简单的指针

指针也是一种变量,它所表示的不是数据的值,而是存储着数据 的内存的地址。通过使用指针,就可以对任意指定地址的数据进行读 写。大家在 Windows 计算机上使用的程序通常都是 32 位(4 字节)的内存地址。 这种情况下,指针变量的长度也是 32 位

指针变量长度都一样,那么之所以要定义成不同类型的指针变量,是因为这些数据类型表示的是从指针存储的地址中一次能够读写的数据字节数。

4 数组是高效使用内存的基础

数组是指多个同样数据类型的数据在内存中连续排列的形式。作 为数组元素的各个数据会通过连续的编号被区分开来,这个编号称为 索引(index)索引和内存地址的变换工作则是由编译器自动实现的。

5 栈、队列以及环形缓冲区

队列,都可以不通过指定地址和索引来对数组的元素进行读 写。需要临时保存计算过程中的数据、连接在计算机上的设备或者输入 输出的数据时,都可以通过这些方法来使用内存。

栈和队列的区别在于数据出入的顺序是不同的。在对内存数据进 行读写时,用的是 LIFO(Last Input First Out,后入先出)方式,而 队列用的则是 FIFO(First Input First Out,先入先出)方式。如果我们 在内存中预留出栈和队列所需要的空间,并确定好写入和读出的顺序, 就不用再指定地址和索引了。



队列一般是以环状缓冲区(ring buffer)的方式来实现的

6 链表使元素的追加和删除更容易

链表二叉查找树,都是不用考虑索引的顺序就可 以对数组元素进行读写的方式。通过使用链表,可以更加高效地对数 组数据(元素)进行追加删除处理。而通过使用二叉查找树,则可以 更加高效地对数组数据进行检索

在数组的各个元素中,除了数据的值之外,通过为其附带上下一 个元素的索引,即可实现 链表由于链表末尾的元素没有后续的数据,因此就需要用别的 值(在这里是-1)来填充

6.1 如何往链表中删除数据

当第 2 个元 素的下一个元素变成第 4 个元素后,那么第 3 个元素就被删除了。 虽然第 3 个元素在物理内存上还残留着,但在逻辑上则确实被删除了

6.2 如何往链表中追加数据

对于数组

7 二叉查找树使数据搜索更有效

二叉查找树是指在链表的基础上往数组中追加元素时,考虑到数 据的大小关系,将其分成左右两个方向的表现形式。

例如,假设我们 事先把 50 这个值保存到了数组中。那么,如果接下来的值比先前保存 的数值大的话,就要将其放到右边,反之如果小的话就放在左边。但 实际的内存并不会分成两个方向,这是在程序逻辑上实现的(图 4-15)。

使用二叉查找树的便利之处在于可以使数据的搜索等更有效率。 在使用一般的数组时,必须从数组的开头按照索引顺序来查找目标数 据。而使用二叉查找树时,当目标数据比现在读出来的数据小时就可 以转到左侧,反之目标数据较大时即可转到链表的右侧,这样就加快 了找到目标数据的速度。

原文地址:https://www.cnblogs.com/cmi-sh-love/p/chengd-xu-shi-zen-yang-pao-qi-lai-de-du-shu-bi-jidi.html