数据结构与算法系列(二):关于数组,我想探讨两个问题

前言

时间与空间复杂度之后还会继续深刻,目前能够先搁置一边。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。

固然,实现上述结果的前提还有下面的两点:

  • i 和 数组 a 类型相同,或者说两者的类型占用字节数相同
  • 所选用语言没有对数组越界作出限制

这个程序还能够进行扩展,留到下次进行分析。

大小端问题

上面是数组如何存储的,那么数组中的某一个元素又是如何存储的?好比 int i = 5 ,其又是如何存储的呢?

栈是一种数据结构,其本质是被操做系统管理的内存空间。变量 i 的存储确定不是依靠操做系统来完成的,那么是谁呢?

咱们写好了某个语言的程序,程序须要转换成机器语言即01010这种二进制语言才可以被计算机识别,这一过程多是由编译器来完成也多是由翻译器来完成。

好比 i 转换成机器语言后能够用十六进制表示成 “0x00000005”(展开就是01010二进制),CPU须要读取指令并执行,那么当它收到这个数字时,又是如何解读的呢?

假设 int 为 4 字节大小,那么一种解读规则是:内存中的低位地址存储 i 的高位字节,即:

0x00 0x1000
... ...
0x05 0x1003

这种存储模式就称为 大端存储

而另一种模式则反过来,以下表:

0x05 0x1000
... ...
0x00 0x1003

这种存储模式就称做为 小端存储

只有编译器(解释器)和 CPU 对于多字节数据的存储模式相统一,才可以正确执行程序。

拓展阅读

  • 《深刻理解计算机系统》
  • 大小端
  • 进程模型
相关文章
相关标签/搜索