高维数组中行向量的访问

  • A访问的是A数组的首地址(即第一个元素的地址)
  • 高维数组采用的均为行主序的内存排列方式
  • 若A为二维数组,则A【i】相当于访问A数组第i行的地址,得到的是一个指针(第i行第0个元素的地址)。此处极易错误理解成A【i】会给出第i行的所有元素!!
  • 机器指令得到第index行的起始地址

  • 机器指令得到第index行dig列数组的值

    嵌套数组(多维数组)在C语言中,如何作为函数参数传递到函数内部并使用

  • 嵌套数组作为参数传递主要有三种方法:
  1. 以定长数组传递。将数组在函数参数表中声明为固定大小的数组(如16*16),这样声明之后,在函数内部直接当数组A为16*16大小的二维数组,使用时可直接用双中括号方法访问。但灵活性有欠缺,无论传入何种数组,都会当作此定长数组处理
  2. 传指针处理。通过指针传递,可以传递变长数组。在传参方式中,把高维数组退化为一维数组,使用一维数组下标的访问方法访问高维数组。通过行主序实现一维和高维下标的转换,先算出第i行间隔,再算出j列间隔,总间隔加在一起得到下标
  3. 更友好、更安全的传参方式,在最新版本gcc中提供支持。将A[N][N]变长数组,直接在参数表中传递进来。但是其维长信息必须在参数表声明A[N][N]数组前,以参数形式首先传入,这样编译阶段才能通过。在使用时直接通过双中括号方法访问。值得注意的是,n的定义一定要在声明A[N][N]数组前,在后边定义会导致编译不通过。

    数组访问的机器级实现:

  • 定长传递的数组
  1. 首先将rsi左移64位(i*64,每一列16个元素,每个元素占4个字节)
  2. a+64*i得到第i行首地址,+4*j得到最终结果

    由上可知,虽然在C语言内部并没有用到16这个常数,但是转换成汇编指令后,使用16作为汇编信息,获得第i行首地址时用到(16*4)。这也说明了,为何无论传进来数组是何种情况,在实际内部处理时,均当做此定长数组进行处理

  • 采用双中括号访问的变长数组

  1. 采用这种方式传递变长数组时,尽管函数体中并未使用n,但转换成汇编语言中用到n进行汇编运算。因此n必须在声明数组前定义,否则编译会出错

多层数组

  • 与嵌套数组不同,是一种利用指针构造出来的复合数组。把所有指向一维数组的指针再使用一个数组存储起来,得到的结构叫做多层数组
  • 多层数组的三个特点
  1. 以指针数组定义的多层数组,其内部存储数据的空间,不一定是连续的空间,只需局部连续即可(每个指针内部连续),不必整体连续
  2. 多层数组中每一行长度不固定,不一定是矩形,更为灵活
  3. 相比嵌套数组,多层数组在存储内容之外,还需要空间存储各行向量的指针,会消耗额外内存空间。
  • 在对多层数组进行访问时,从C语言级别上看,与嵌套数组访问是相似的,采用双中括号方式访问
  • 但内部访问函数是不同的,多层数组首先访问univ下的index元素,得到指针即得到低维数组的首地址,进而得到元素
  • 从汇编级别看二者区别

  1. 多层数组访问过程中会经历两次内存读操作。读取指针数组中要读取指针的地址,来获得低维数组的首地址;读取低维数组中要获取的元素的地址,获取相应元素。因为多层数组不存储在一片连续的内存中间,我们要首先在uivn查到指针,再根据指针查对应位置的元素,要经过两次内存访问才能实现
  2. 嵌套数组只有最后取数据才涉及到读内存操作,之前都是计算偏移量,只计算地址,不读取地址。因为嵌套数组是连续存储的,其中每个内存位置可以由嵌套数组首地址结合下标来得到

多层数组和嵌套数组的比较

  • 从C语言角度没有区别,都采用双中括号形式访问
  • 编译汇编指令时会得到不同的汇编指令。
  • C语言中默认的高维数组是嵌套数组,但支持自己构造多维数组。即先构造指针数组,然后在每个指针中存储一个低维数组。而Java支持的高维数组是多层数组,不支持嵌套数组。因为Java把数组本身看做由引用实现,而多层数组的本质就是引用

无欲则刚
76 声望16 粉丝