如何利用栈恢复数组初始值?汇编随机字符串生成问题
汇编作业:生成独立随机字符串并输出
问题说明
课堂作业要求实现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
问题根源
- 输出长度错误:
writeLoop使用LENGTHOF arrayString(固定为100)作为循环次数,会输出数组中所有内容,包括之前生成的残留字符,导致看起来是字符串累加。 - 数组未有效重置:每次生成新字符串时,仅覆盖数组开头的部分内容,后续旧字符未被清理,但核心问题其实是输出时没有限制到当前字符串的实际长度。
- 寄存器保存无效:push/pop ESI和ECX无法解决问题,因为
CreateRandomString每次都会重新将ESI指向数组起始地址,问题本质不在寄存器状态,而在数组内容的输出逻辑。
解决方案
方案1:修改输出逻辑(最简单高效)
不需要修改数组内容的存储方式,只需记录每次生成的字符串实际长度,输出时仅循环该长度,避免输出旧字符:
- 在
.data段添加变量存储当前字符串长度:currentLength DWORD ? - 修改
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 - 可选:若需要彻底清空数组中本次长度外的内容,可在
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
相关产品推荐
相关产品推荐

