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

如何利用栈恢复数组初始值?汇编随机字符串生成问题

汇编作业:生成独立随机字符串并输出

问题说明

课堂作业要求实现CreateRandomString proc,每次生成随机长度(0-99)、内容为随机大写字母的字符串并存入arrayString;main proc中的writeLoop需要遍历输出20次,每次输出独立的新字符串。

当前程序可运行,但由于全局数组arrayString未正确重置,新字符串会在旧内容后累加,最终导致输出混乱甚至程序崩溃。尝试过在storeLoop前后push/pop ESI和ECX,但未解决问题。刚接触汇编,想了解如何用栈解决该问题,或得到其他可行的修改建议。使用Irvine32库的RandomRange proc(传入EAX=100时生成0-99的随机数)。

当前代码

;.386
;.model flat,stdcall
;.stack 4096
;ExitProcess proto,dwExitCode:dword
INCLUDE Irvine32.inc

.data
arrayString BYTE 100 DUP (?)
mainLoopCounter DWORD 20

.code

CreateRandomString proc
    mov ESI, OFFSET arrayString
    mov ECX, EAX ;Length of string

storeLoop:
    mov EAX, 26
    call RandomRange
    add EAX, 65
    mov BYTE PTR [ESI], AL
    inc esi
    loop storeLoop
    call CRLF
    ret
CreateRandomString endp
main proc
    call Randomize
mainL:
    mov EAX, 100
    call RandomRange
    call CreateRandomString

    mov ESI, OFFSET arrayString
    mov ECX, LENGTHOF arrayString
writeLoop:
    mov AL, BYTE PTR [ESI]
    call WriteChar
    inc ESI
    loop writeLoop
    mov ECX, mainLoopCounter
    dec mainLoopCounter
    loop mainL

    Invoke ExitProcess,0
main endp
end main

问题根源

  1. 输出长度错误:writeLoop使用LENGTHOF arrayString(固定为100)作为循环次数,会输出数组中所有内容,包括之前生成的残留字符,导致看起来是字符串累加。
  2. 数组未有效重置:每次生成新字符串时,仅覆盖数组开头的部分内容,后续旧字符未被清理,但核心问题其实是输出时没有限制到当前字符串的实际长度。
  3. 寄存器保存无效:push/pop ESI和ECX无法解决问题,因为CreateRandomString每次都会重新将ESI指向数组起始地址,问题本质不在寄存器状态,而在数组内容的输出逻辑。

解决方案

方案1:修改输出逻辑(最简单高效)

不需要修改数组内容的存储方式,只需记录每次生成的字符串实际长度,输出时仅循环该长度,避免输出旧字符:

  1. 在.data段添加变量存储当前字符串长度:
    currentLength DWORD ?
    
  2. 修改main proc中的逻辑,保存随机长度并用于输出循环:
    main proc
        call Randomize
    mainL:
        mov EAX, 100
        call RandomRange
        mov currentLength, EAX ; 保存本次生成的字符串长度
        call CreateRandomString
    
        mov ESI, OFFSET arrayString
        mov ECX, currentLength ; 使用实际长度作为输出循环次数
    writeLoop:
        mov AL, BYTE PTR [ESI]
        call WriteChar
        inc ESI
        loop writeLoop
        call CRLF ; 输出完一个字符串后换行,提升可读性
    
        dec mainLoopCounter
        mov ECX, mainLoopCounter
        loop mainL
    
        Invoke ExitProcess,0
    main endp
    
  3. 可选:若需要彻底清空数组中本次长度外的内容,可在CreateRandomString开头添加清空逻辑:
    CreateRandomString proc
        mov ESI, OFFSET arrayString
        mov ECX, EAX ; 本次字符串长度
        ; 清空本次要写入的区域(可选,避免极端情况)
    clearLoop:
        mov BYTE PTR [ESI], 0
        inc ESI
        loop clearLoop
        mov ESI, OFFSET arrayString ; 重置ESI到数组开头
        mov ECX, EAX ; 恢复长度
    
    storeLoop:
        mov EAX, 26
        call RandomRange
        add EAX, 65
        mov BYTE PTR [ESI], AL
        inc esi
        loop storeLoop
        ret
    CreateRandomString endp
    

方案2:用栈实现字符串生成(满足栈用法需求)

栈适合临时存储数据,利用栈的后进先出特性生成字符串,需注意字符顺序问题:

CreateRandomString proc
    mov EBX, EAX ; 保存字符串长度
    mov ECX, EAX
    ; 循环生成字符并压入栈
pushLoop:
    mov EAX, 26
    call RandomRange
    add EAX, 65
    push EAX ; 将字符压入栈(32位栈操作,取AL部分即可)
    loop pushLoop

    ; 将栈中字符弹出到数组,注意栈是后进先出,需从数组末尾往前写入
    mov ESI, OFFSET arrayString
    add ESI, EBX
    dec ESI ; 指向数组中本次字符串的最后一个位置
    mov ECX, EBX
popLoop:
    pop EAX
    mov BYTE PTR [ESI], AL
    dec ESI
    loop popLoop

    ret
CreateRandomString endp

此方法通过栈临时存储字符,再逆序弹出到数组保证顺序正确,适合练习栈操作,但对于当前问题并非最优解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 20:42:28