我有问题:
从用户获取输入直到输入“ z”或“ Z”的程序
该程序将检查字符,并打印
(新行)小字符
(新行)大字符
(新行)数字
[没有'z'或'Z']
不能使用变量。
只有堆栈。
例如:
输入:ASdf154sdgdf123vcvbz
小字符:dfsdgdfvcvb
大字符:AS
编号:154123
具有字符串大小的程序定义N,程序将从用户处获取输入,并且仅从输入中获取数字并将其放入具有N大小的字符串中,输入大小为N。并打印带有字符串的消息(必须只输入数字)和数量。
示例(字符串大小10)
输入:1adr1t23g7
字符串:11237
打印输出:
数字字符串是:11237,总数字是:5
被问题1困扰,对主题不了解,无法继续问题2。 感谢所有可以帮助我的人
这是问题1的代码:
STA SEGMENT STACK
DB 100H DUP (0)
STA ENDS
CODE SEGMENT
ASSUME CS:CODE,SS:STA
MAIN:
MOV BP, SP
MOV BX, BP
SUB BP, 2
MOV CX, 0
INPUT:
MOV AH, 01H
INT 21H
INC CX
CMP AL, 'z'
JE TOPRINT
CMP AL, 'Z'
JE TOPRINT
MOV AH, 0
PUSH AX
MOV AX, 0
JNE INPUT
MOV DI, CX
TOPRINT:
POP DX
CMP DX, 'a'
JL NEXT
CMP DX, 'z'
JG NEXT
MOV AH, 02H
INT 21H
CMP DX, 'A'
JL NEXT
CMP DX, 'Z'
JG NEXT
MOV AH, 02H
INT 21H
CMP DX, '0'
JL NEXT
CMP DX, '9'
JG NEXT
MOV AH, 02H
INT 21H
NEXT:
SUB BP, 2
DEC CX
CMP CX, 0
JMP TOPRINT
MOV AX, 4C00H
INT 21H
CODE ENDS
END MAIN
答案 0 :(得分:0)
好吧,似乎该任务旨在锻炼堆栈使用情况,并发表您的评论:
不了解主题
似乎是准确的。但是,然后您要人们将本书的简短章节写成简单的SO答案……嗯,通常我不喜欢这样做,因为整本书是完整的书,简短的答案将不得不省略一些细节,但是让我们尝试是否有减少的东西可以作为答案:
16b实模式下的堆栈内存是普通的计算机内存,但是寄存器对ss:sp
指向“堆栈顶部”,并且有多个指令隐式地使用这两个寄存器来访问内存,例如{{ 1}}确实“将存储器地址pop dx
上的字值读入寄存器ss:sp
,然后将2加到dx
(以使其指向存储器中的下一个字)”(意义为“ 16位信息”,而不是“文本”字。
记下关于push / pop指令的说明(请查看指令指南,无论是Intel的官方文档,还是https://www.felixcloutier.com/x86/之类的基础知识),sp
确实会从push
中减去,即堆栈从高内存地址向低内存地址“增长”,并且当您sp
时,pop
返回高内存地址。 “堆栈顶部”是最后一个被推入的堆栈,位于当前地址sp
上。推入堆栈的上一个项目位于ss:sp
(在16b模式下),等等...因此,如果您要使用ss:sp+2
进行寻址,并将bp
的值复制到{{ 1}}在最后sp
将项目存储到堆栈之后,则可以使用bp
寻址来访问您的项目(注意:push
默认情况下与[bp+0], [bp+2], [bp+4], ...
段相关,因此{ {1}}是隐式bp
(从堆栈段中加载值),而ss
默认是隐式mov ax,[bp]
(从数据段中加载)..除非您明确指定其他段覆盖源代码)。
还要注意指令mov ax,ss:[bp]
和mov ax,[bx]
,它们也隐式地使用堆栈,因此您会开始使用mov ax,ds:[bx]
/ call
指令来使用子例程吗?在子程序内部时,堆栈数据的结构还将包含返回地址(进入子程序时位于“堆栈顶部”)。
在emu8086中的代码中,您通过在代码的开头定义堆栈段来保留堆栈的内存区域,保留256个字节(128个字),对于像这样的重堆栈任务,这是非常小的堆栈,例如代码将以“每输入一个字符一个字”的速度吃掉堆栈,您最多可以输入128个字符...这似乎是合理的,直到您了解到DOS中断也使用了实际的用户堆栈,这有两个主要结果:
ret
下的内存会被DOS中断处理程序定期覆盖您的任务听起来像您可以做到的:
call
固定为正确的时间),或者空堆栈的“结束”指针)现在,您可能会很想在第一个“遍历所有输入值”中进行ret
的操作,但这意味着您可以将ss:sp
向上移至原始的“空堆栈” ...并且如果然后从pop
中减去2 *个项目,您可能会认为您现在可以再次从内存中pop
进行相同的字符了,通过ss:sp
修改作弊。但是,如果同时发生某些中断,则sp
以下的原始字符会被销毁,因此前两个循环不要pop
。
宁可使用sp
来访问数据,即在每个输出循环之前访问ss:sp
,然后循环执行项-多次执行pop
bp
,但保持{{ 1}}不变(并将项目副本的数量保留在某处,因此您可以在第二和第三循环中使用它……或在开始时将“空” mov bp,sp
复制到类似mov dl,[bp]
的地方,以进行{{1 }}检查输出循环(如果您已仔细阅读所有项目)。
如果您不太熟悉汇编程序设计主题,并且对我的大部分文本感到迷惑,请先阅读一些书或教程。有关寄存器/内存/等的基础知识通常可以从此摘要中{{3 }}的目标是32位模式,但是我不了解16b的简短介绍(我想您的讲师会给您一些建议,学习什么),或者使用google ...请记住16b模式更加棘手比32b模式更困难,因为您还必须了解内存段,并且内存寻址受到更多限制(add bp,2
在16b模式下不存在,而ss:sp
在32b模式下是合法的)。
如果您仅对某些特定部分有疑问,请提出评论。
然后看一下代码,学习使用调试器(这是绝对必要的,将stackoverflow web用作调试服务效率较低,并且许多人(包括我在内)都认为这是粗鲁和不良的行为...如果可以证明您已经调试了代码,并且可以很好地描述令人困惑的行为(正在发生的事情以及您想要/期望的事情),将会有更多的人愿意为您写答案,为什么会发生以及思维过程在哪里出错),并尝试使用上述信息将其重写。