「这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战」。
一维数组的定义
数组本质上就是多个数据的集合,在内存中按照一定顺序排列,角标即为每个数据的偏移值,在mips中内存数据是按照4个字节进行对齐的,也就是说一个数据最少占用4个字节内存空间,因此数组中数据之间的偏移量固定为n*4
.data
array: .space 20 #别名的另外一种用法 通过array(寄存器)这种格式 寄存器中存放地址偏移地址量
.text
# $t0寄存器存放角标值 $s1中存放需要存入的值
li $s1,1
li $t0,0
sw $s1,array($t0) #相当于 sw $s1,array+$t0
li $s1,2
li $t0,4
sw $s1,array($t0)
li $s1,3
li $t0,8
sw $s1,array($t0)
数组的打印
.data
array: .space 20
.text
#初始化数组中的数据
li $s1,1
li $t0,0
sw $s1,array($t0)
li $s1,2
li $t0,4
sw $s1,array($t0)
li $s1,3
li $t0,8
sw $s1,array($t0)
#查找角标为2的数值
getData:
la $s1 ,array
li $a0,2
mul $a0,$a0,4
add $s1,$s1,$a0
lw $a0,0($s1)
li $v0,1
syscall
#将角标临时置为0 方便下面循环操作
li $t0,0
while:
beq $t0,12,exit
lw $t2,array($t0)
addi $t0,$t0,4
li $v0,1
move $a0,$t2
syscall
j while
exit:
li $v0,10
syscall
快速初始化数组数据的方法
.data
array: .word 20 :3 #批量定义3个整型数据20
二维数组的定义
二维数组其实就类似于我们数学中的二维坐标系,我们如果要定位一个点的话可以使用(x,y)来表示,在计算机的世界里,二维中所有的点都按照顺序依次存放在内存当中
假设我们将第一维当做行,第二维当做列,那么排列的方式有以下两种:
第一种是 行不动,列轮动
内存地址 | 二维坐标 |
---|---|
0x00000020 | arr[2][2] |
0x0000001C | arr[2][1] |
0x00000018 | arr[2][0] |
0x00000014 | arr[1][2] |
0x00000010 | arr[1][1] |
0x0000000C | arr[1][0] |
0x00000008 | arr[0][2] |
0x00000004 | arr[0][1] |
0x00000000 | arr[0][0] |
这种方式获取实际地址的公式为:
addr=baseAddr+(rowIndex*colSize+colIndex)*dataSize
实际地址=首地址+(第几行*总列数+第几列)*数据占用的宽度
比如:我要计算arr[2][1]的实际物理地址, 那么
实际地址=0x00000000+(2*3+1)*4=0x00000000+0x0000001C=0x0000001C
第二种是 列不动,行轮动
内存地址 | 二维坐标 |
---|---|
0x00000020 | arr[2][2] |
0x0000001C | arr[1][2] |
0x00000018 | arr[0][2] |
0x00000014 | arr[2][1] |
0x00000010 | arr[1][1] |
0x0000000C | arr[0][1] |
0x00000008 | arr[2][0] |
0x00000004 | arr[1][0] |
0x00000000 | arr[0][0] |
这种方式获取实际地址的公式为:
addr=baseAddr+(colIndex*rowSize+rowIndex)*dataSize
实际地址=首地址+(第几列*行数+第几行)*数据占用的宽度
比如:我要计算arr[2][1]的实际物理地址, 那么
实际地址=0x00000000+(1*3+2)*4=0x00000000+0x00000014=0x00000014
使用mips汇编实现二维数组定义
#需求:实现int a[3][3] = {{1, 2, 3}, {5, 6, 7}, { 10, 11, 12}};
#以下是以 行不动 列轮动的方式实现
.data
da: .word 1,2,3,5,6,7,10,11,12
array: .space 36
.text
# void initArry(*arr,row,col,index)
initArry:
#首地址
la $a0,array
#第几行
li $a1,0
#第几列
li $a2,0
#存第几个数
li $a3,0
while:
# arr[x][y]
bgt $a1,2,exit
# 避免寄存器中的参数被子函数覆盖 将数据放置在栈中临时保存
add $sp,$sp,-12
sw $a1,8($sp)
sw $a2,4($sp)
sw $a3,0($sp)
jal saveDataToMemory
#从栈中恢复局部变量值
lw $a1,8($sp)
lw $a2,4($sp)
lw $a3,0($sp)
add $sp,$sp,12
#累加计数
add $a3,$a3,4
#列轮动
addi $a2,$a2,1
bgt $a2,2,sub
j while
sub:
li $a2,0
add $a1,$a1,1
j while
saveDataToMemory:
# 避免寄存器中的参数被子函数覆盖 将数据放置在栈中临时保存
add $sp,$sp,-4
sw $ra,0($sp)
#计算数据存放的物理地址
jal getAddr
#获取需要存放的数据
lw $t0,da($a3)
#将数据存入指定位置中
sw $t0,0($v0)
lw $ra,0($sp)
add $sp,$sp,4
jr $ra
#算法部分
getAddr:
#实际地址=首地址+(第几行*总列数+第几列)*数据占用的宽度
mul $a1,$a1,3
add $a2,$a2,$a1
mul $a2,$a2,4
add $v0,$a2,$a0
jr $ra
exit:
#程序结束之前测试数据能否正常取出
jal getDataFromArry
li $v0,10
syscall
#获取指定坐标位置的数据arr[2][1] 输出值为11
getDataFromArry:
#第几行
li $a1,2
#第几列
li $a2,1
#计算物理地址
jal getAddr
#获取数据
lw $t0,0($v0)
#打印数据
move $a0,$t0
li $v0,1
syscall
列不不动 行轮动方式:
#需求:实现int a[3][3] = {{1, 2, 3}, {5, 6, 7}, { 10, 11, 12}};
#以下是以 列不动,行轮动的方式实现
.data
da: .word 1,2,3,5,6,7,10,11,12
array: .space 36
.text
# void initArry(*arr,row,col,index)
initArry:
#首地址
la $a0,array
#第几行
li $a1,0
#第几列
li $a2,0
#存第几个数
li $a3,0
while:
# arr[x][y]
bgt $a2,2,exit
# 避免寄存器中的参数被子函数覆盖 将数据放置在栈中临时保存
add $sp,$sp,-12
sw $a1,8($sp)
sw $a2,4($sp)
sw $a3,0($sp)
jal saveDataToMemory
#从栈中恢复局部变量值
lw $a1,8($sp)
lw $a2,4($sp)
lw $a3,0($sp)
add $sp,$sp,12
#累加计数
add $a3,$a3,4
#行轮动
addi $a1,$a1,1
bgt $a1,2,sub
j while
sub:
li $a1,0
add $a2,$a2,1
j while
saveDataToMemory:
# 避免寄存器中的参数被子函数覆盖 将数据放置在栈中临时保存
add $sp,$sp,-4
sw $ra,0($sp)
#计算数据存放的物理地址
jal getAddr
#获取需要存放的数据
lw $t0,da($a3)
#将数据存入指定位置中
sw $t0,0($v0)
lw $ra,0($sp)
add $sp,$sp,4
jr $ra
#算法部分
getAddr:
#实际地址=首地址+(第几列*行数+第几行)*数据占用的宽度
mul $a2,$a2,3
add $a1,$a1,$a2
mul $a1,$a1,4
add $v0,$a1,$a0
jr $ra
exit:
#程序结束之前测试数据能否正常取出
jal getDataFromArry
li $v0,10
syscall
#获取指定坐标位置的数据arr[2][1] 输出7
getDataFromArry:
#第几行
li $a1,2
#第几列
li $a2,1
#计算物理地址
jal getAddr
#获取数据
lw $t0,0($v0)
#打印数据
move $a0,$t0
li $v0,1
syscall
更为简便的方法实现二维数组的搭建
由于数组中数据是在内存中连续进行排列存储的,那么我们可以之间将数据 依次存入内存之中,然后使用算法进行数据获取即可(以下示例皆采用 行不动,列动 的方式)
#需求:实现int a[3][3] = {{1, 2, 3}, {5, 6, 7}, { 10, 11, 12}};
#由于数组中的数据是存放在堆内存中,需要在程序执行时动态分配
.text
#堆地址从0x10040000开始
la $a0,0x10040000
#将数据按照顺序存放至内存中
jal initData
#获取数据
jal getDataFromArry
j exit
initData:
li $s1,1
sw $s1,0($a0)
li $s1,2
sw $s1,4($a0)
li $s1,3
sw $s1,8($a0)
li $s1,5
sw $s1,12($a0)
li $s1,6
sw $s1,16($a0)
li $s1,7
sw $s1,20($a0)
li $s1,10
sw $s1,24($a0)
li $s1,11
sw $s1,28($a0)
li $s1,12
sw $s1,32($a0)
jr $ra
#算法部分
getAddr:
#实际地址=首地址+(第几行*总列数+第几列)*数据占用的宽度
mul $a1,$a1,3
add $a2,$a2,$a1
mul $a2,$a2,4
add $v0,$a2,$a0
jr $ra
exit:
#程序退出
li $v0,10
syscall
#获取指定坐标位置的数据arr[2][1] 输出值为11
getDataFromArry:
#第几行
li $a1,2
#第几列
li $a2,1
#计算物理地址
jal getAddr
#获取数据
lw $t0,0($v0)
#打印数据
move $a0,$t0
li $v0,1
syscall
再简化一下:
#需求:实现int a[3][3] = {{1, 2, 3}, {5, 6, 7}, { 10, 11, 12}};
.data
da: .word 1,2,3,5,6,7,10,11,12
# 假如以上数据是动态写入的 当做数组中的数据来用
.text
#那么只需要提供首地址然后配合算法就能获取到指定坐标的数据
la $a0,da
jal getDataFromArry
j exit
#算法部分
getAddr:
#实际地址=首地址+(第几行*总列数+第几列)*数据占用的宽度
mul $a1,$a1,3
add $a2,$a2,$a1
mul $a2,$a2,4
add $v0,$a2,$a0
jr $ra
exit:
#程序退出
li $v0,10
syscall
#获取指定坐标位置的数据arr[2][1] 输出值为11
getDataFromArry:
#第几行
li $a1,2
#第几列
li $a2,1
#计算物理地址
jal getAddr
#获取数据
lw $t0,0($v0)
#打印数据
move $a0,$t0
li $v0,1
syscall
按照正常的编程思维,我们一般使用第一种行不动 列动的存储方式 第一维为行,第二维为列,如果你想改成行动存储方式,有两种方法:要么将数据的存储顺序进行变动,配合第二种算法,要么将第二维当成行,第一维当成列,配合第二种算法进行处理