You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NASM中统计单个字符在字符串中出现次数的实现问题

NASM汇编统计字符出现次数问题修正

需求说明

实现统计指定字符在字符串中的出现次数,例如比对字符为"a"、字符串为"haha"时,计数结果应为2。核心思路为加载字符串地址到寄存器,逐字节比对内存字符与目标字符,更新计数器后继续处理。

现有代码

SECTION .data               ; Initialize data
    cmp_char db "a", 0h
    word1    db "harp", 0h
    word2    db "haha" , 0h

SECTION .text
    global _start           ; Initialize starting point for program

_start:                     ; Program entry point
    jmp check_for_vowel     ; Jumps to "check_for_vowel" function

check_for_vowel:
    push EDX                ; Preserve EDX on the stack; restore after function runs
    push ECX                ; Preserve ECX on the stack; restore after function runs
    push EBX                ; Preserve EBX on the stack; restore after function runs
    push EAX                ; Preserve EAX on the stack; restore after function runs

    mov EDX, 0              ; Initialize char counter

    mov AH, [cmp_char]      ; Load value of "cmp_char" into AH, an 8-bit subsection of EAX
    mov EBX, word1          ; Move address of word1 to EBX.

loop_counter:
    mov AL, Byte [EBX]      ; Move value of BX into AL, an 8-bit subregister of EAX
    cmp AL, 0h              ; Check if value in AL is 0...
    jz finished             ; ... and if it is, jump to "finished" function.

    cmp AL, AH              ; Else, compare the Bytes in AL and AH...
    jz match                ; ... and if they match, jump to the "match" function.
    
    inc ECX                 ; Otherwise, increment the loop counter...
    inc EBX                 ; ... and loop to the next character in the string...
    jmp loop_counter        ; ... and start the loop over again.

match:
    inc EDX                 ; Increment the char counter.
    inc EBX                 ; Loop to the next character in the string.
    jmp loop_counter        ; Jump back to the loop_counter.

finished:
    ret

问题分析

  1. 栈平衡与程序退出问题:_start作为程序入口直接跳转至check_for_vowel,但该函数开头push了寄存器,结尾用ret返回——此时栈中无合法返回地址,会导致程序崩溃。Linux下程序需通过exit系统调用正常退出。
  2. 冗余寄存器操作:ECX被push保存,但loop_counter中inc ECX属于无效操作,字符串地址已通过EBX递增,无需额外循环计数器。
  3. 缺少结果输出逻辑:代码仅完成计数,未将EDX中的数值转换为ASCII并输出,无法看到最终结果。
  4. 不必要的数据定义:cmp_char定义为db "a", 0h,实际仅需取第一个字节,末尾的0h多余(不影响功能但可简化)。

修正后的代码

SECTION .data
    cmp_char db "a"          ; 仅存储目标字符,无需额外0
    word1    db "harp", 0h
    word2    db "haha", 0h
    newline  db 0xA          ; 换行符用于输出格式

SECTION .text
    global _start

_start:
    mov EDX, 0               ; 初始化计数器为0
    mov AH, [cmp_char]       ; 加载目标字符到AH
    mov EBX, word2           ; 可切换为word1或word2测试

count_loop:
    mov AL, byte [EBX]       ; 读取当前字符到AL
    cmp AL, 0                ; 判断是否到字符串结束符
    jz print_result          ; 结束则跳转至输出

    cmp AL, AH               ; 比对当前字符与目标字符
    jz increment_counter     ; 匹配则跳转至计数递增

next_char:
    inc EBX                  ; 地址递增,处理下一个字符
    jmp count_loop

increment_counter:
    inc EDX                  ; 计数器+1
    jmp next_char

print_result:
    ; 将十进制计数转换为ASCII(支持0-9,需更大数值可扩展多位数转换)
    add EDX, '0'             ; 数字转ASCII字符
    mov [newline-1], DL      ; 临时存储转换后的字符

    ; 调用write系统调用输出计数
    mov EAX, 4               ; sys_write系统调用号
    mov EBX, 1               ; 文件描述符stdout
    mov ECX, newline-1       ; 输出字符地址
    mov EDX, 1               ; 输出长度1
    int 0x80

    ; 输出换行
    mov EAX, 4
    mov EBX, 1
    mov ECX, newline
    mov EDX, 1
    int 0x80

    ; 调用exit系统退出程序
    mov EAX, 1               ; sys_exit系统调用号
    xor EBX, EBX             ; 退出码0
    int 0x80

关键修改说明

  • 移除不必要的寄存器push/pop操作,避免栈平衡问题。
  • 删除冗余的ECX递增操作,仅通过EBX管理字符串地址。
  • 添加计数转ASCII的逻辑(针对0-9的小数值,需支持更大计数可扩展多位数转换)。
  • 增加write系统调用实现结果输出,以及exit系统调用保证程序正常退出。
  • 简化cmp_char的定义,去掉多余的结束符。

内容的提问来源于stack exchange,提问作者user14178703

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 05:05:15