Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 在用户输入中查找第一个和最后一个大写字母_Assembly_Emu8086 - Fatal编程技术网

Assembly 在用户输入中查找第一个和最后一个大写字母

Assembly 在用户输入中查找第一个和最后一个大写字母,assembly,emu8086,Assembly,Emu8086,输入取自a-z或a-z,输入以星号*结束 我们需要输入字符的第一个和最后一个大写字母作为输出。此外,我们还应显示每次所做的输入。注意:我们一个字符接一个字符地接受输入,而不是字符串 测试用例1:输入:aAbCcP*输出:AP 测试用例2:输入:ZabCBc*输出:ZB 我在下面编写了这段代码,它满足测试用例1,但不满足测试用例2: .MODEL .STACK 100H .DATA STR DB 'Enter letters:$' .CODE MAIN PROC MOV AX, @DAT

输入取自a-z或a-z,输入以星号*结束

我们需要输入字符的第一个和最后一个大写字母作为输出。此外,我们还应显示每次所做的输入。注意:我们一个字符接一个字符地接受输入,而不是字符串

测试用例1:输入:aAbCcP*输出:AP

测试用例2:输入:ZabCBc*输出:ZB

我在下面编写了这段代码,它满足测试用例1,但不满足测试用例2:

.MODEL
.STACK 100H
.DATA
   STR DB 'Enter letters:$'
.CODE

MAIN PROC

MOV AX, @DATA
MOV DS, AX

LEA DX, STR
MOV AH, 9
INT 21H 

cycle: 

    MOV AH, 1
    INT 21H

    CMP AL, '*'
    JZ output 
    CMP AL, 'Z' 
    JA save


head: 
    CMP BL, 1
    JZ save

    MOV BL, 1
    MOV BH, AL 

clear:
    XOR AL, AL  

save:
    MOV CH, AL

LOOP cycle 

output:
    MOV AH, 2
    MOV DL, BH
    INT 21H 

    MOV AH, 2
    MOV DL, CH
    INT 21H 


MAIN ENDP 
END MAIN 
首先问自己以下问题: 什么是首都? 如果我们不考虑重音字符,那么大写字母是ASCII码的字符,范围从65到90。 我可以信任用户只输入a-z或a-z中的字符吗? 不,你不能。你无法控制用户在键盘上做什么,这就是为什么你的程序应该采取防御性的方法,用比单个cmp al“Z”更好的东西来测试大写字母

如果输入不包含单个资本,结果会是什么? 您可以选择打印两个空格,或者一条描述性消息,或者像我一样什么也不显示

如果输入只包含一个资本,结果会是什么? 你可以选择打印一个大写字母,或者像我一样显示两次,因为如果你想一想,这个大写字母同时是大写字母的第一次出现,也是大写字母的最后一次出现

我将使用哪些输入/输出函数? 对于单字符输入,您可以在DOS功能01h、06h、07h、08h、0Ch和3Fh之间进行选择。 对于单字符输出,您可以在DOS函数02h、06h和40h之间进行选择。 如果您对组装还不熟悉,请坚持使用更简单的,并使用函数01h和02h。在使用任何DOS功能之前,请务必咨询。当然,请使用emu8086检查它是否完全支持该功能

为了完成这项任务,你需要决定以上所有事项。重要的是,对于你做出的每一个选择,你都可以捍卫自己的选择

下面是我对这项任务的看法。为了简单起见,我使用了微型程序模型。请参阅顶部的ORG 256指令?该程序模型的主要优点是,所有段寄存器都平等地指向您的程序CS=DS=ES=SS

程序运行2个循环。第一个循环运行,直到收到资金。不言而喻,如果输入包含星号,它会提前停止。因为资本同时是资本的第一次出现,也是资本的最后一次出现,所以我在DL和DH中保存了两次

第二个循环运行,直到收到星号。每次出现新的大写字母时,它都会替换DH中所写的字母。当这个循环最终结束时,DL和DH都显示在屏幕上,当然是按这个顺序显示的

程序使用首选DOS功能4Ch退出,以终止程序

我已经写了一些重要的注释,避免添加多余的注释,并在程序中为标签使用描述性名称。请注意,这是一个很好的表格布局。对于可读性来说,这是关键

        ORG     256

Loop1:  mov     ah, 01h     ; DOS.GetKeyboardCharacter
        int     21h         ; -> AL
        cmp     al, "*"     ; Found end of input marker ?
        je      Done
        cmp     al, "A"
        jb      Loop1
        cmp     al, "Z"
        ja      Loop1
        mov     dl, al      ; For now it's the first
        mov     dh, al      ; AND the last capital

Loop2:  mov     ah, 01h     ; DOS.GetKeyboardCharacter
        int     21h         ; -> AL
        cmp     al, "*"     ; Found end of input marker ?
        je      Show
        cmp     al, "A"
        jb      Loop2
        cmp     al, "Z"
        ja      Loop2
        mov     dh, al      ; This is the latest capital
        jmp     Loop2

Show:   mov     ah, 02h     ; DOS.DisplayCharacter
        int     21h         ; -> (AL)
        mov     dl, dh
        mov     ah, 02h     ; DOS.DisplayCharacter
        int     21h         ; -> (AL)

Done:   mov     ax, 4C00h   ; DOS.TerminateWithReturnCode
        int     21h
例如:

阿泽蒂*

aZeRTy*ZT

如果你简单地复制/粘贴我的代码,那将是非常令人失望的。我试着详细解释,希望你能从中学到很多东西

对于这项任务,我的解决方案当然不是唯一好的解决方案。例如,您可以先输入所有字符并将其存储在内存中的某个位置,然后再从内存中处理这些字符,类似于我的处理方式。
请尝试编写一个工作版本,以这种替代方式完成。你只能变得更聪明!快乐编程。

您的代码被破坏了,因为每次迭代都要保存:MOV CH,AL,所以只有当最后一个大写字母也是整个输入的最后一个字符时,它才能工作

用一个调试器对ABc*这样的简单输入进行单步调试,看看它是如何出错的

此外,您还可以使用类似于dec-cx/jnz的循环。这毫无意义,因为不存在基于计数器的终止条件,并且如果CL为零,可能会损坏CH。你甚至不先初始化CX!循环指令不是循环的唯一方式;这只是一个代码大小的窥视孔优化,当您方便地将CX用作循环计数器时,可以使用它。否则不要使用它

这是Sep实现的简化版本,利用了输入保证为字母的事实,因此我们确实可以像检查c一样轻松地检查大写字母,您的代码在案例2中打印了什么?这不是一个好主意。还要用英语注释您的代码和/或描述您的算法应该是什么,哪些寄存器应该包含什么。我不明白为什么你有一个明确的标签:当没有跳转的时候。你只会从头上掉下去。此外,在循环开始之前,您似乎在读取BL时从未将BL或BX归零。您的代码似乎不正确
依靠BL!=1。此外,循环会根据CX提前结束,或者循环指令会损坏CH。我认为您需要jmp,因为没有基于计数的循环终止条件。循环基本上是dec cx/jnz,但没有更新标志,因此显然您不希望这样。无论如何,最明显的问题是,每次循环都会更新CH。仅当最后一个大写字符也是最后一个全局字符时,它才能工作。您可以编写两个循环:一个循环找到第一个大写字母并将其保存在一个寄存器中,然后另一个循环跟踪最后一个大写字母。OP已经在使用cmp al“Z”。我不确定你的第一个要点是什么。他们可以假定他们的输入是字母,所以c>'Z'表示小写,否则表示大写。您的版本使用额外的分支来拒绝非字母字符,从而使其复杂化。但是,是的,两个单独的循环似乎是最好的选择,而不是每次您找到新大写字母时都在一个标志上分支。@PeterCordes我的答案是根据OP得出的。我错误地将其发布在这里。尽管如此,我认为这仍然是一个有效的答案。是的,这个问题应该被删除或关闭,因为这是一个重复。也许可以简化第一个要点,因为OP已经知道了这一点。或者强调排除非字母字符,使代码更加复杂,但能够处理输入,如12ABcd7_,如果您对代码大小进行优化,您也可以删除:mov ax,4C00h;DOS.TerminateWithReturnCode int 21h以Done:ret为受益人。COM程序可以通过简单的ret终止。DOS将在堆栈顶部推送0000h,然后再将控制权转移到CS:100h。CS:0000h是PSP的开始,包含int 20h指令,该指令又返回DOS。@MichaelPetch:heh,我没有考虑优化算法本身之外的内容,但我猜在.com文件中没有任何其他开销如此确定。int 20h是否通过ret设置退出状态=0?我在google上找到的所有东西都称之为无退出状态,除非DOS退出状态类似于标志+值或可以编码非a状态而不是数字的东西,否则没有意义。
        ORG     100h        ; DOS .com is loaded with IP=100h, with CS=DS=ES=SS
                            ; we don't actually do any absolute addressing so no real effect.

        mov     ah, 01h     ; DOS.GetKeyboardCharacter
                            ; AH=01 / int 21h doesn't modify AH so we only need this once
find_first_cap:  
        int     21h         ; stdin -> AL
        cmp     al, '*'     ; Found end of input marker ?
        je      Done        ;  if (c=='*') return;  without print anything, we haven't found a capital yet

        cmp     al, 'Z'
        ja      find_first_cap
    ; fall through: AL <= 'Z' and we can assume it's a capital letter, not a digit or something.

        mov     dl, al      ; For now it's the first
        ;mov     dh, al      ; AND the last capital

        ;mov     ah, 01h     ; DOS.GetKeyboardCharacter   AH still = 01
        ;jmp     loop2_entry      ; we can let the first iteration set DH
Loop2:                      ; do {
        cmp     al, 'Z'       ; assume all c <= 'Z' is a capital alphabetic character
        ja      loop2_entry
        mov     dh, al        ; This is the latest capital

loop2_entry:
        int     21h         ; stdin -> AL
        cmp     al, '*'
        jne     Loop2       ; }while(c != '*');


Show:   mov     ah, 02h     ; DOS.DisplayCharacter
        int     21h         ; AL -> stdout
        mov     dl, dh
        ; mov     ah, 02h     ; DOS.DisplayCharacter
        int     21h         ; AL -> stdout

Done:   mov     ax, 4C00h   ; DOS.TerminateWithReturnCode
        int     21h