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

前言

时间与空间复杂度以后还会继续深入,目前可以先搁置一边。

​ 数据结构与算法中,最基本的两个结构就是:数组、链表。二者最大的区别在于:数组存储地址是连续的,链表存储地址不是(完全)连续的。

​ 数组可以说的没有多少,一是因为简单;二是因为有很多文章都讲的很详细。所以我们不再赘述,本片对数组引出的两个问题进行探讨:

  • 栈的生长方向以及数组的偏移
  • 大小端问题

栈的生长方向及数组偏移

引用一张 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;
}
复制代码

运行后,输出为:

j is 5

为什么?

因为上述程序在执行 (1)之前,由于(1)之前的变量都是局部变量,所以存储在栈中。而上文说过了,栈的生长方向是向下的,且数组的元素地址是递增的,所以(1)之前的内存(栈)布局为:

所以,当数组越界访问 a[3] 时,就越界到了 i = 5 的位置,所以就会将 5 赋值给 j。

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

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

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

大小端问题

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

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

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

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

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

0x000x1000
......
0x050x1003

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

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

0x050x1000
......
0x000x1003

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

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

拓展阅读

  • 《深入理解计算机系统》
  • 大小端
  • 进程模型

转载于:https://juejin.im/post/5c63e36ef265da2d8963130f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值