引言
首先,毫无疑问的说数组下标都是从0开始的。
其次,对于一维数组,数组是线性数据结构,内存空间的地址是连续的。
然而,对于二维数组,不同语言可能有所区别。
不同编程语言的内存管理是不一样的,本文分析了Go、C++、java三种语言的二维数组的内存地址布局。
Go 二维数组
Go中二维数组是连续分布的。
我们来做一个实验,Go测试代码如下:
package main
import "fmt"
func main() {
var intArr [2][3]int ;
// 默认为零
// [[0 0 0] [0 0 0]]
// 赋值
intArr[1][0] = 1
intArr[1][1] = 2
intArr[1][2] = 3
// 遍历二维数组 for-range
// 0 0 0
// 1 2 3
for _,values := range intArr {
for _ ,val := range values {
fmt.Print(val," ")
}
fmt.Println()
}
// 二维数组在内存的布局
//
// intArr的地址0xc000086030
// intArr[0]的地址0xc000086030
// intArr[0][0]的地址0xc000086030
// intArr[0][1]的地址0xc000086038 0xc000086038 = 0xc000086030 + 8
// intArr[0][2]的地址0xc000086040 0xc000086040 = 0xc000086038 + 8
// intArr[1]的地址0xc000086048 0xc000086048 = 0xc000086030 + 8*3
// intArr[1][0]的地址0xc000086048
// intArr[1][1]的地址0xc000086050 0xc000086050 = 0xc000086048 + 8
// intArr[1][2]的地址0xc000086058 0xc000086058 = 0xc000086050 + 8
// 遍历二维数组 for
fmt.Printf("intArr的地址%p \n\n",&intArr)
for i := 0; i <len(intArr); i++ {
fmt.Printf("intArr[%v]的地址%p \n",i,&intArr[i])
for j:=0; j < len(intArr[i]);j++{
fmt.Printf("intArr[%v][%v]的地址%p \n",i,j,&intArr[i][j])
}
fmt.Println()
}
}
地址为16进制,可以看出二维数组地址是连续一条线性的。
友友可能看不懂内存地址,我就简单介绍一下, 0xc000086040 与 0xc000086048 差了一个8,就是8个字节,因为这是一个int型的数组,所以两个相邻数组元素地址差8个字节。
C++ 二维数组
C++中二维数组也是连续分布的。
我们来做一个实验,C++测试代码如下:
#include <iostream>
using namespace std;
int main()
{
int array[2][3] = {
{0, 1, 2},
{3, 4, 5}
};
cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl;
//0x7ffc3ba35620 0x7ffc3ba35624 0x7ffc3ba35628
//0x7ffc3ba3562c 0x7ffc3ba35630 0x7ffc3ba35634
return 0;
}
可以看出在C++中二维数组在地址空间上是连续的。0x7ffc3ba35628 与 0x7ffc3ba3562c 差了一个4,C++中int型占4字节,所以两个相邻数组元素地址差4个字节。
Java 二维数组
Java是没有指针的,同时也不对程序员暴露其元素的地址,寻址操作完全交给虚拟机。
所以看不到每个元素的地址情况,这里我以Java为例,也做一个实验。
public class Main
{
public static void main(String[] args) {
int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
// [I@5fdef03a
// [I@3b22cdd0
// [I@1e81f4dc
// [I@4d591d15
}
}
这里的数值也是16进制,这不是真正的地址,而是经过处理过后的数值了,我们也可以看出,二维数组的每一行头结点的地址是没有规则的,更谈不上连续。
所以Java的二维数组可能是如下排列的方式:
总结
不同编程语言的内存管理是不一样的,对于二维数组,Go和C++语言的地址空间是连续的,而Java语言中不同行之间的地址是无序的。