实验三 循环程序设计
一、实验目的
1. 掌握 loop 指令。
2. 掌握while和do while循环结构。
3. 掌握伪指令.while和 .repeat。
4. 掌握一维数组处理的常用算法。
二、实验内容
1.有一个首地址为array的10个有符号的双字数组,编程分别求出偶数和与奇数和并输出。
偶数和:
include vcIO.inc
include io32.inc
.data
array dword 12,34,123,78,43,234,79,86,98,20
esum dword ?
.code
start:
mov ecx,lengthof array
xor eax,eax
mov esi,eax
again:
mov ebx,array[esi*4]
test ebx,1
jnz next
add eax,ebx
next:
inc esi
loop again
mov esum,eax
call dispuid
exit 0
end start
奇数和:
include vcIO.inc
include io32.inc
.data
array dword 12,34,123,78,43,234,79,86,98,20
esum dword ?
.code
start:
mov ecx,lengthof array
xor eax,eax
mov esi,eax
again:
mov ebx,array[esi*4]
test ebx,1
jz next
add eax,ebx
next:
inc esi
loop again
mov esum,eax
call dispuid
exit 0
end start
思考题:将求和改为求(1)最大值与最小值 (2)正数和与负数和 (3)素数和
最大值与最小值
include vcIO.inc
include io32.inc
.data
msg1 byte '输出最大值',10,0
msg2 byte '输出最小值',10,0
fmts byte '%s',0
fmtd byte '%d',10,0
array dword 12,34,123,78,43,234,79,86,98,20
max dword ?
min dword ?
.code
start:
mov ecx,lengthof array -1
mov eax,array[0]
mov ebx,eax
mov esi,1
.while(ecx!=0)
cmp eax,array[esi*4]
jge small
mov eax,array[esi*4]
small:
cmp ebx,array[esi*4]
jle next
mov ebx,array[esi*4]
next:
inc esi
dec ecx
.endw
mov max,eax
invoke printf,offset fmts,offset msg1
invoke printf,offset fmtd,max
mov min,ebx
mov eax,ebx
invoke printf,offset fmts,offset msg2
invoke printf,offset fmtd,min
exit 0
end start
正数和与负数和
include io32.inc
.data
array sdword -4,-2,-1,-6,-5,0,1,2,1,4,5
sum_gz sdword 0
sum_lz sdword 0
msg_gz byte '正数和=',0
msg_lz byte '负数和=',0
.code
main:
mov ecx,lengthof array-1
xor eax,eax ;sum_gz
mov ebx,eax ;sum_lz
mov esi,eax
;在使用伪代码时,如果存在负数,则有必要加上 sdword ptr
.while sdword ptr ecx>=0
mov edx,array[esi*4]
.if sdword ptr edx>0
add eax,edx
.endif
.if sdword ptr edx<0
add ebx,edx
.endif
inc esi
dec ecx
.endw
mov sum_gz,eax
mov eax,offset msg_gz
call dispmsg
mov eax,sum_gz
call dispsid
call dispcrlf
mov sum_lz,ebx
mov eax,offset msg_lz
call dispmsg
mov eax,ebx
call dispsid
exit 0
end main
素数和
include io32.inc
include vcio.inc
.data
array dword 1,4,-2,3,-1,5,7,-3,0,2
primeSum dword 0 ;素数和
msg byte '素数和为',0
.code
start:
mov ecx,lengthof array
mov esi,0
again:
mov eax,array[esi*4]
cmp eax,0
jle next ;判断是否是素数
cmp eax,1
je sum
jmp isPrime ;非无符号数,下一个
isPrime:
mov ebx,2
.while ebx<eax
xor edx,edx
div ebx
cmp edx,0
jz next
inc ebx
.endw
sum:
mov eax,array[esi*4]
add primeSum,eax
next:
inc esi
loop again
mov eax,offset msg
call dispmsg
mov eax,primeSum
call dispsid
exit 0
end start
2.有一个首地址为array的10个有符号的双字数组,编程逆置数组并输出。
include io32.inc
.data
array dword 10,11,9,8,7,6,3,1
count equ lengthof array
.code
main:
mov esi,0
mov edi,count-1
.while(esi<edi)
mov eax,array[esi*4]
xchg eax,array[edi*4]
mov array[esi*4],eax
inc esi
dec edi
.endw
mov ecx,count
mov esi,0
again:
mov eax,array[esi*4]
call dispsid
call dispcrlf
inc esi
dec ecx
jnz again
exit 0
end main
3. Fibonacci numbers的定义: f1=1,f2=1, fn= fn-1 + fn-2 n>=3 编程输出Fibonacci numbers的前30项。
include vcIO.inc
include io32.inc
.data
fmtc byte 10,'counter=%6u',0
fmt byte '%10u',0
.code
main proc
invoke printf,offset fmt,1
invoke printf,offset fmt,1
mov ecx,2
mov esi,1
mov edi,esi
again:
add esi,edi
pushad
invoke printf,offset fmt,esi
popad
cmp ecx,31
je over
inc ecx
xchg esi,edi
jmp again
over:
dec ecx
invoke printf,offset fmtc,ecx
ret
main endp
end main
思考题:在不产生溢出的情况下n的最大值是多少?
include vcIO.inc
include io32.inc
.data
fmtc byte 10,'counter=%7u',0
fmt byte '%10u',0
.code
main proc
invoke printf,offset fmt,1
invoke printf,offset fmt,1
mov ecx,2
mov esi,1
mov edi,esi
again:
add esi,edi
jc over
inc ecx
pushad
invoke printf,offset fmt,esi
popad
xchg esi,edi
jmp again
over:
invoke printf,offset fmtc,ecx
ret
main endp
end main
4.编程写一个完整的程序,求出2012年~2099年中的所有闰年年份,存入Lyear数组中,并输出所有闰年。(可考虑控制每行输出5个年份)提示:采用伪代码描述如下:
esi=0 ;闰年个数计数器;
ecx=2012 ;年份计数器;
while (ecx<2100)
{
if (year mod 4=0 and year mod 100 <>0) or (year mod 400=0) then
{ Lyear[esi]=ecx; //Lyear[esi] 为存放闰年的数组
esi++;}
ecx++;
}
Lcounter=esi ;Lcounter 闰年个数
include vcIO.inc
include io32.inc
.data
year dword ?
lyear dword 100 dup(?)
.code
main proc
mov esi,0
mov year,2012
.while year<=2099
mov eax,year
xor edx,edx
mov ebx,400
div ebx
cmp edx,0
jz leap
mov eax,year
xor edx,edx
mov ebx,4
div ebx
cmp edx,0
jnz noleap
mov eax,year
xor edx,edx
mov ebx,100
div ebx
cmp edx,0
jz noleap
leap:
mov eax,year
call dispuid
call dispcrlf
mov lyear[esi*4],eax
inc esi
noleap:
inc year
.endw
ret
main endp
end main
5.有一个首地址为string的字符串 ,分别统计string中空格、大写英文字母的个数并输出。
include vcIO.inc
include io32.inc
.data
msg byte 'ab efg AB 12 !@#',10,0
space dword ?
lowercase dword ?
fmtstr byte '空格=%d 小写字母=%d',10,0
.code
main proc
mov ecx,lengthof msg-1
xor eax,eax
mov ebx,eax
mov esi,offset msg
again:
mov dl,[esi]
cmp dl,' '
jnz letter
inc eax
letter:
cmp dl,'a'
jb next
cmp dl,'z'
ja next
inc ebx
next:
inc esi
loop again
mov space,eax
mov lowercase,ebx
invoke printf ,offset fmtstr,eax,ebx
ret
main endp
end main
思考题:还可继续统计空格、小写英文字母、数字和其它字符的个数并输出。
6. palindrome(回文)是指正读和反读都一样的数或文本。例如:11、121、12321等,编写程序,求10到10000之间所有回文数并输出。要求每行输出10个数。( 提示:采用div指令把整数分解为单个的数字,并将它们组合成一个新的整数。)
include vcIO.inc
include io32.inc
.data
msg byte 13,10,0
fmts byte '%s',0
fmtd byte '%7d',0
.code
main proc
mov edi,0
mov ecx,10
mov ebx,ecx
.while ecx<=10000
xor esi,esi
mov eax,ecx
.while(eax!=0)
xor edx,edx
div ebx
imul esi,10
add esi,edx
.endw
cmp esi,ecx
jne next
mov eax,ecx
pushad
invoke printf,offset fmtd,eax
popad
inc edi
.if edi==10
pushad
invoke printf,offset fmts,offset msg
popad
mov edi,0
.endif
next:
inc ecx
.endw
ret
main endp
end main
思考题:测试一字符串是否为“回文串”。
7. 有一个首地址为string 的字符串,剔除string 中所有的空格字符。请从字符串最后一个字符开始逐个向前判断、并进行处理。
include vcIO.inc
include io32.inc
.data
string byte ' i love huibian ,and you?',0
fmtd byte '%s'
.code
start:
mov esi,lengthof string-1
mov edi,lengthof string-1
.while sdword ptr esi>=0
cmp string[esi],20h
jnz next
inc esi
mov ebx,esi
.while ebx<=edi
mov al,string[ebx]
mov string[ebx-1],al
inc ebx
.endw
dec edi
next:
dec esi
.endw
mov byte ptr string[edi+1],0
mov eax,offset string
call dispmsg
exit 0
end start
三、回答问题:
1. 在循环结构中,如何避免无限循环情况的发生?
使用确定循环条件真能结束的条件,如不能保证假定的循环结束条件是否真能发生,则应设置循环次数,在汇编语言的loop指令中中,一般设置eax>0。
2. 下面的程序段中,循环体将被执行多少次?如果的初值为-100,循环体将被执行多少次?
mov ecx,0
loopTest: mov eax,ecx
call dispuid
loop loopTest
当前循环体,ecx为零,循环体循环;当ecx为-100时,循环体被执行的次数为