时间与空间复杂度之后还会继续深刻,目前能够先搁置一边。linux
数据结构与算法中,最基本的两个结构就是:数组、链表。两者最大的区别在于:数组存储地址是连续的,链表存储地址不是(彻底)连续的。算法
数组能够说的没有多少,一是由于简单;二是由于有不少文章都讲的很详细。因此咱们再也不赘述,本片对数组引出的两个问题进行探讨:windows
引用一张 linux 进程内存结构的图,其中 stack 栈的生长方向是向下生长的,也就是向低地址生长,即好比从 0x10008 - 0x00010。windows的栈也是向下生长。而咱们都知道,数组的元素和其对应的地址是往大增加的:数组
好比:int a[2] = {0}
, 其中数组 a 的地址为0x00010,那么a[1] 的地址应该是 0x00010 + 1 * sizeof(int)
。数据结构
正是由于这种区别,考虑到以下的 C 程序 :布局
#include <stdio.h>
int main() {
int i = 5;
int a[3] = {0};
int j = 6;
j = a[3]; // (1)
printf("j is : %d", j); // (2)
return 0;
}
复制代码
运行后,输出为:ui
j is 5spa
为何?操作系统
由于上述程序在执行 (1)以前,因为(1)以前的变量都是局部变量,因此存储在栈中。而上文说过了,栈的生长方向是向下的,且数组的元素地址是递增的,因此(1)以前的内存(栈)布局为:翻译
因此,当数组越界访问 a[3]
时,就越界到了 i = 5
的位置,因此就会将 5 赋值给 j。
固然,实现上述结果的前提还有下面的两点:
这个程序还能够进行扩展,留到下次进行分析。
上面是数组如何存储的,那么数组中的某一个元素又是如何存储的?好比 int i = 5
,其又是如何存储的呢?
栈是一种数据结构,其本质是被操做系统管理的内存空间。变量 i 的存储确定不是依靠操做系统来完成的,那么是谁呢?
咱们写好了某个语言的程序,程序须要转换成机器语言即01010这种二进制语言才可以被计算机识别,这一过程多是由编译器来完成也多是由翻译器来完成。
好比 i 转换成机器语言后能够用十六进制表示成 “0x00000005”(展开就是01010二进制),CPU须要读取指令并执行,那么当它收到这个数字时,又是如何解读的呢?
假设 int 为 4 字节大小,那么一种解读规则是:内存中的低位地址存储 i 的高位字节,即:
0x00 | 0x1000 |
---|---|
... | ... |
0x05 | 0x1003 |
这种存储模式就称为 大端存储
而另一种模式则反过来,以下表:
0x05 | 0x1000 |
---|---|
... | ... |
0x00 | 0x1003 |
这种存储模式就称做为 小端存储
。
只有编译器(解释器)和 CPU 对于多字节数据的存储模式相统一,才可以正确执行程序。