汇编语言:如何正确输出字符串中出现次数最多的字符
问题分析与修复
你的代码存在三个核心问题,导致字符显示异常:
1. 计数数组的定义与访问不匹配
你将counts定义为resb 256(256字节),但代码中访问计数时使用了eax *4的偏移(比如inc byte [counts + eax *4]),并且在查找最大值时按双字(4字节)读取数据。这会导致:
- 内存越界:当字符ASCII值超过63时(63*4=252,接近256字节边界),后续访问会超出
counts的分配空间。 - 计数读取错误:按双字读取字节数组会把连续4个字节当成一个计数,导致数值错误。
修复:将counts改为双字数组:
counts resd 256 ; 每个元素是4字节的计数,对应一个ASCII字符
2. max_char赋值错误
在find_max_loop中,你错误地将计数值的低字节存入max_char(mov [max_char], al),但此时eax存储的是当前字符的出现次数,而非字符本身的ASCII码。这就是为什么输出时显示带框问号——你在打印一个非可打印的控制字符(计数值对应的ASCII)。
修复:计算当前计数对应的字符ASCII值:当前edi指向counts数组的某个元素,字符的ASCII值等于(edi - counts)/4(因为每个计数占4字节)。将这个值存入max_char:
; Update max_char and max_count mov eax, [edi] mov ebx, edi sub ebx, counts ; ebx = 当前元素的偏移量 shr ebx, 2 ; 偏移量除以4,得到字符的ASCII值 mov [max_char], bl ; 存入max_char mov dword [max_count], eax
3. fgets参数错误
fgets的第二个参数是缓冲区的最大长度,你传入了string_length(仅100字节),但input_string分配了256字节。这会导致输入超过100字符时被截断,甚至可能引发缓冲区溢出。
修复:直接传入input_string的大小256:
push dword [stdin] push dword 256 ; 缓冲区大小 push input_string call fgets add esp, 12
修正后的完整代码
%include "asm_io.inc" section .data dash db "-------------------------------------------------", 0 progTitle db "Find the maximum occurring character in a string", 0 enter_string_prompt db "Enter a string: ", 0 output_format db "The highest frequency of character '%c' appears number of times is %d",0 section .bss input_string resb 256 max_char resb 1 max_count resd 1 counts resd 256 ; 每个元素是4字节的计数,对应一个ASCII字符 section .text extern printf, fgets, stdin global asm_main asm_main: push ebp mov ebp, esp mov eax, dash call print_string call print_nl mov eax, progTitle call print_string call print_nl mov eax, dash call print_string call print_nl ; prompt mov eax, enter_string_prompt call print_string push dword [stdin] push dword 256 push input_string call fgets add esp, 12 mov esi, input_string count_loop: movzx eax, byte [esi] cmp al, 0 je end_count_loop ; Skip counting spaces cmp al, ' ' je skip_increment inc dword [counts + eax * 4] ; 按双字计数 skip_increment: inc esi jmp count_loop end_count_loop: mov ecx, 256 mov edi, counts mov eax, [edi] ; Initialize eax with the first count ; 初始化max_char为第一个字符(ASCII 0) mov byte [max_char], 0 mov dword [max_count], eax find_max_loop: cmp dword [edi], eax jl next_char ; Update max_char and max_count mov eax, [edi] mov ebx, edi sub ebx, counts shr ebx, 2 mov [max_char], bl mov dword [max_count], eax next_char: add edi, 4 loop find_max_loop movzx eax, byte[max_char] push eax push dword [max_count] push output_format call printf add esp, 12 call print_nl leave ret
额外说明
- 初始化
max_char时添加了mov byte [max_char], 0,确保初始状态有合法的字符值。 - 计数时改为
inc dword [counts + eax *4],匹配双字数组的访问方式。
内容的提问来源于stack exchange,提问作者Pran Emm
相关产品推荐
相关产品推荐

