MIPS汇编语言之一维数组和二维数组定义

1,688 阅读6分钟

「这是我参与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)来表示,在计算机的世界里,二维中所有的点都按照顺序依次存放在内存当中

假设我们将第一维当做行,第二维当做列,那么排列的方式有以下两种:

第一种是 行不动,列轮动

内存地址二维坐标
0x00000020arr[2][2]
0x0000001Carr[2][1]
0x00000018arr[2][0]
0x00000014arr[1][2]
0x00000010arr[1][1]
0x0000000Carr[1][0]
0x00000008arr[0][2]
0x00000004arr[0][1]
0x00000000arr[0][0]

这种方式获取实际地址的公式为:

addr=baseAddr+(rowIndex*colSize+colIndex)*dataSize

实际地址=首地址+(第几行*总列数+第几列)*数据占用的宽度

比如:我要计算arr[2][1]的实际物理地址, 那么
实际地址=0x00000000+(2*3+1)*4=0x00000000+0x0000001C=0x0000001C

第二种是 列不动,行轮动

内存地址二维坐标
0x00000020arr[2][2]
0x0000001Carr[1][2]
0x00000018arr[0][2]
0x00000014arr[2][1]
0x00000010arr[1][1]
0x0000000Carr[0][1]
0x00000008arr[2][0]
0x00000004arr[1][0]
0x00000000arr[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

按照正常的编程思维,我们一般使用第一种行不动 列动的存储方式 第一维为行,第二维为列,如果你想改成行动存储方式,有两种方法:要么将数据的存储顺序进行变动,配合第二种算法,要么将第二维当成行,第一维当成列,配合第二种算法进行处理