2016-11-25 81 views
3

我一直在处理这个程序,我必须输入一个字符串,然后在该字符串中显示字符分布。在程序集x86中查找字符串中的出现次数

例如:
如果输入是“minecode”输出应该是

Ç - 1
-O - 1
d - 1
ë - 2
I - 1
M - 1
N - 1

这是我试图做的,但我真的不知道如何遍历循环并检查相似的字符,然后增加计数。汇编程序是在32位机器上运行的MASM 615。

.686 
.MODEL flat, stdcall 
.STACK 
INCLUDE Irvine32.inc 
.DATA 
    msg0 BYTE "Enter a string of characters: ",0 
    msg1 BYTE "Character Distribution: ",0 
    MainArray dword 10000 dup (?) 
    UniqueChar dword 10000 dup (?) 
    CharCount dword 10000 dup (?) 
.CODE 
MAIN PROC 
    lea edx, msg0 
    call WriteString 
    call dumpregs  ; 1 
    call ReadString 
    mov MainArray, eax 
    call dumpregs  ; 2 
    mov MainArray, ebx 
    call dumpregs  ; 3 
    call CRLF 
    lea edx, msg1 
    call WriteString 
    call CharDist  ; Calls the procedure 
    call dumpregs  ; 5 
    exit 
MAIN ENDP 
CharDist PROC 
    mov ecx, lengthof MainArray 
    mov esi, OFFSET MainArray 
    L1: 
; what to do here?? 
Loop L1: 
CharDist ENDP 
END MAIN 
+4

'循环L1:'是语法错误。您只在定义标签时使用尾部的':',而不是从别处引用它。 (并且首先不要使用LOOP,[它很慢并且没有做任何事情,只要用更常见的指令就可以轻松完成](http://stackoverflow.com/questions/35742570/why-is ) - –

回答

5

一个可能的方法:使256个计数器阵列,存储其基地址在ebx,并为字串中的每个字节,递增在从ebx偏移计数器。之后,循环您的计数器阵列并打印非零计数。

你永远不会说这是一个由0字节(C风格),一个以其长度(Pascal样式)开头还是一个长度作为第二个参数传入的字符串,但这将决定当你终止循环。如果您正在查找终止零,请测试您刚刚读取的字节,并且如果要计算特定数量的字节,请将剩余的字节数保留在ecx并测试该字节数。 (有分支特殊说明有条件如果ecx不为零,如果你觉得使用它们。)

如果你把你的字符串指针在esi,你可以下一个字节与lodsb指令加载到al。或者,您可以从[esi]mov然后inc esi。如果在将每个字节存储在al之前,将eax置零,则会为您提供eax中的索引,您可以将其与一组计数器一起使用。

+1

是的,只有256个bin足够小,可以使一个标准的直方图方法适用于普通数组,而不是散列表或其他地图数据结构。 –

+5

但是,您使用LOOP指令来实现循环的建议并不好。在大多数CPU上,[它很慢,你可能忘记它甚至存在](http://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-它有效),除非优化代码大小。我建议的另一件事是在循环内使用'movzx eax,byte [esi]''inc [table + eax]'。这可能比将循环外部的eax调零然后修改循环内的低字节(例如使用LODSB)更容易。虽然这两种方式都有效。 –

+1

我肯定会建议OP在尝试使用汇编语言实现哈希表之前获取简单的方法。 – Davislor

3

其他可能的方法:

应该是比较容易理解,实际上这是非常“人性化”简单(就像你会怎么做它用铅笔纸),所以我不知道你怎么没来了这个......你不仅应该试着去理解它是如何工作的,还应该试着弄清楚为什么你没有看到它,什么让你困惑/阻塞。

for all letters of alphabet [A-Z] as "letter" { 
    counter = 0; 
    for all characters in input string as "char" { 
     if (letter ignore_case_equals char) ++counter; 
    } 
    if (0 < counter) { 
     display "letter - counter" and new line. 
    } 
} 

对于英文字母和短字符串,这可能实际上更快,就像3-5个字母(仅包含字母);比建议的计数排序,因为字母表是26个字符,计数表是256个字节,所以256/26 =〜9。但计数表将显示任何字符的计数,包括非字母表的字符,并且它在分支上的停顿也较少。


还要注意,你是如何开始与发射代码提示/输入/等等的东西你已经可以在大会做,避免了不明。

我确实从几乎英文的算法描述开始。因为我不在乎,我知道我在汇编中写什么(我已经知道,几乎任何东西:)),首先我想确定我知道我想要代码为我做什么以及我想要什么样的数据处理。然后,我会命令CPU做到这一点,通过完成数据结构计划并将这些英文笔记分成更简单和更简单的步骤,直到它们开始类似于指令,然后填写评论之间的指令。

不要跳过本地语言推理阶段,它可以为您节省大量的代码工作,如果您找出一些优雅的方式来组织数据或通过重用某些部分来减少算法步骤。并不是每个问题都有短暂优雅的解决方案,但很多都有。

+3

根据你如何实现count-matches部分,该部分可以是无分支的(CMP /'sete al' /'add ecx,eax')。条件打印的'0

+0

如果您可以保证只有字母,那么您可以优化桶的阵列,使其更快!但是这也是有效的,尝试多种方法是很好的。 – Davislor

相关问题