当前位置: 首页 > 知识库问答 >
问题:

MASM 移动具有嵌套循环的数组元素

谢翰学
2023-03-14

使用您的姓氏初始化 BYTE 数组,而不是以 0 结尾的字符串。使用嵌套循环和索引寻址,编写一个程序,该程序在外部循环的每次迭代中将数组成员向前旋转一个位置。数组开头的值必须绕到最后一个位置。例如,在外部循环的第一次迭代之后,“S”、“m”、“i”、“t”、“h”应转换为“m”、“i”、“t”、“h”、“S”。每次旋转后使用作者的库函数之一显示数组。使用外部循环的正确迭代次数将名称恢复为其原始拼写。内循环应执行旋转。

我无法在我的生命中弄清楚,如果有人能提供任何帮助,我会很感激。我对组装非常陌生,并不真正了解嵌套循环。我也不知道如何移动字母。这就是我到目前为止所拥有的

INCLUDE Irvine32.inc
WriteString PROTO

.data
    source BYTE "S", "m", "i", "t", "h"
.code
main PROC
    mov esi, 0
    mov ecx, SIZEOF source
L1 :
    mov al, source[esi]
    inc esi
loop L1
    mov edx, offset source 
    call WriteString
exit
main ENDP
END main

有人能指引我正确的方向吗?

共有2个答案

梁丘兴腾
2023-03-14

我将此代码用于等效问题:

使用循环和索引寻址,编写代码将32位整数数组的成员向前旋转一个位置。数组末尾的值必须绕到第一个位置。例如,数组[10,20,30,40]将转换为[40,10,20,30]

COMMENT !
    Author : Tran Van Nam
    date: 23-Sep- 21
    Shifting the Element in an Array
    Ex8 Trang 138 assembly
!

.386
.model flat, stdcall
.stack 4096


ExitProcess proto, dwExitCode:dword
.data
    array dword 1000h,20000h,30000h,40000h
.code
main proc
mov esi , offset  array     ;esi = point first element in array
mov eax, [esi]              ;
mov ecx, lengthof array -1  ; ecx :contain counter loop
mov edi, 0                  ; index 0 , element last changed
l1:
mov ebx,[esi+type array]        ; assigned EBX with next element 
mov [esi+type array], eax       ; rotate 2 element x and x+1
mov eax, ebx                  ;hold next element,so step previous is changed
add esi, type array             ; point to next element
loop l1

mov array[edi],eax
invoke ExitProcess , 0
main endp
end main

感谢您的收看

景靖琪
2023-03-14

嵌套循环

请记住,整个“循环”是程序员的逻辑概念,而不是CPU的特性(x86确实有字面上称为< code>loop的指令,但不要使用它:为什么循环指令很慢?英特尔难道不能高效地实现它吗?).

是什么造就了循环循环?你有一些被认为是循环的“主体”的代码,你运行它N次,那就是“循环”。

现在嵌套循环正在调用一种情况,其中循环体(外部循环)包含另一个循环(内部循环),该循环将执行例如M次。那么内循环体总共会执行NxM-多次,因为每次外循环一次,内循环就会再运行一次。

简单的 x86 示例:

    ; init outer loop counter (will loop till zero)
    mov     ebp,7
outer_loop_body:
    ; some outer loop body code
    ; init inner loop counter (will loop till zero)
    mov     ecx,5
inner_loop_body:
    ; some inner (nested) loop body code
    ; this inner body will execute 7x5 = 35 many times
    dec     ecx
    jnz     inner_loop_body ; repeat until counter is zero
    ; some other outer loop code
    dec     ebp
    jnz     outer_loop_body ; repeat until counter is zero
    ; this code is outside of loops, executed after them

当然,您必须保留您的计数器(如果寄存器不足,请使用一些内存来存储它们,如果您不太使用它们)。

在您的任务中,它被称为“索引寻址”,并且示例中的倒计时计数器通过值N到1,因此如果您从source数组的末尾开始,它们几乎可以用作索引(只需要-1)。但这有利于“向前一个位置”数据移动和就地内存覆盖,对于向后移动,最好构造具有递增计数计数器的循环,如:

    ; init loop index to go from zero to N-1
    xor     ecx,ecx     ; index = 0
loop_body:
    ; some loop body code, using ECX as index
    ; advance to next index
    inc     ecx
    cmp     ecx,N
    ; loop until value N in index is reached
    jb      loop_body
    ; this code is outside of loop, executed after it

我也不知道如何移动字母。

我几乎会付钱让你看看你的大脑尝试了什么,这让我非常好奇你是如何看待这种问题的,对于一个经验丰富的程序员来说,这是显而易见的,但看起来不是。

我个人从想象数据开始(忽略代码和算法),在你的例子中:

source BYTE "S", "m", "i", "t", "h"

这将在内存中组装为具有值S、m、i、t、h的5个连续字节(对于特定的数值,请检查ASCII表或反汇编)。

现在我想象一下,在第一次迭代向前移动之后,内存应该是什么样子的(我将做向前移动):

source BYTE "h", "S", "m", "i", "t"

离开原始数组的“h”放在第一个位置,以使整个内容循环。

现在我设想一些算法来实现这种数据转换(即从输入数据中计算出期望的结果):

fetch last element and keep it safe for later
loop (from last position down to second position) do:
    read position-1 element, and store it at position
store the original "last element" to first position

我在脑子里快速运行它,以验证它是否进行了我想要的计算,修复任何错误。我做了一些疯狂的快速猜测,需要多少指令来实现特定的步骤,如果它超过cca 5,我会将其分解为更简单的步骤。在这种情况下,感觉每一步大约是2-3个指令(这通常意味着最后大约是x2),所以这种算法的分解对我来说是可以的。

然后我使用它作为基本注释,并用asm指令实现它。

对我来说似乎很明显,我无法想象是什么让你陷入困境。

最后举例说明如何以索引方式覆盖“字节数组”的某些内存:

; assume ESI already contains address of array
; initialized earlier by something like: mov esi, OFFSET source
; and ECX contains index (0..4 value)
mov     al,[esi+ecx-1]    ; loads element from position ECX-1
    ; ^^ will go out of bounds for index 0!
mov     [esi+ecx],al      ; store that element to position ECX

或者,您可以使用另一个 MASM 语法选项,这次将数组地址直接指定为编译时常量:

; ECX contains index (0..4 value)
mov     al,source[ecx-1]    ; loads element from position ECX-1
    ; ^^ will go out of bounds for index 0
mov     source[ecx],al      ; store that element to position ECX

在寄存器中使用基址的第一个选项为您提供了在任何内存阵列上重复使用相同功能的选项,而不仅仅是,因此我更喜欢它而不是第二个变量,否则它们在功能上是相同的。

因此,简而言之,“移动字母”您只需用新内容覆盖原始内存内容,新内容恰好是原始值,但存储到不同的地址(通过-1,取决于您如何理解有问题的“前进”措辞,尽管我相信这个例子是完全错误的,而“前进”是相反的方式)。

如果您在同一个内存中就地这样做,请注意,您必须选择正确的覆盖顺序(对于“向前”,从最后一个位置到第一个位置,或者对于“向后”,从第一个位置到最后一个位置),否则您将把一个元素值复制到其余位置。

现在,我很想听听你在这个问题上没有弄清楚的地方,如果现在清楚了的话。

编辑:还有一个注释…

当然,要使用asm指令实现任何计算,您需要首先了解一些,哪些指令可用,以及它们的功能是什么。它有助于多次通读说明参考指南,以了解哪种计算是可能的。

对于x86,我会从80386 ISA开始,因为它相当短(不包括FP指令和SIMD扩展名),但已经包含了所有常见的基本x86指令,例如google从Intel找到了一些原始PDFhttp://css.csail.mit.edu/6.858/2013/readings/i386.pdf,第3、4、5和17章相关(或网络版http://css.csail.mit.edu/6.858/2014/readings/i386/c17.htm ).

并确保你清楚地了解什么是CPU寄存器,它们有多少个,它们的“大小”是多少,对最小/最大值意味着什么,什么是计算机内存以及它是如何工作的。即关于x86计算机体系结构的基本内容。

那么“用指令实现注释”这一步应该是可管理的(随着经验的增长,甚至没有开始时那么难)。

 类似资料:
  • 使用嵌套循环 我仍在努力实现上述问题所述的目标。基本上我的代码现在是这样的: 这很烦人,我不明白为什么会这样! 我想计算地球因太阳和月亮而产生的加速度。所以我有双[]行星质量={earthMass,sunMass,moonMass},一系列粒子物体粒子[]行星={earth,sun,moon}和一系列由于重力而产生的加速度,它们还没有被计算出来:物理矢量[]gravField={earthGrav

  • 例如,我有一个这样的数组 但输出只有11、12、13、14、15。我想打印所有的值。有人能帮我修改一下吗?提前谢谢

  • 我试图弄清楚嵌套for循环是如何与JavaScipt中的多维数组一起工作的,但有一点让我有些困惑。以股票为例 这就是我所期望的结果123456。但是,如果我将数字添加到外部数组的末尾: 我仍然得到同样的输出1 2 3 4 5 6?我不明白为什么 输出是一个bcdyz,这是我所期望的。为什么字符串的行为会有所不同?

  • 问题内容: 我不知道这是否是一个愚蠢的问题,但是我需要在不使用递归的情况下动态更改for循环的数量。 例如,如果n = 3,则需要3个嵌套的for循环。 如果n = 5: 有没有什么方法可以做到这一点而无需递归?另一个问题:Java中多重调度的用途是什么?我正在尝试用一种方法编写代码,它应该在参数的不同情况下运行不同的事件。否,如果声明/三元经营者/案件。 注意:我只能使用一种方法(部分问题),并

  • 问题内容: 为了练习Java 8流,我尝试将以下嵌套循环转换为Java 8流API。它计算a ^ b(a,b <100)的最大数字总和,并在我的Core i5 760上花费约0.135s。 我的解决方案由于并发现象而预计会更快,实际上花了0.25s(不带的时间为0.19s ): 我的问题 我执行转换正确吗,还是有更好的方法将嵌套循环转换为流计算? 为什么流变种比旧变种慢得多? 为什么paralle

  • 我有一个这样的数组 我想做的是前面的模型,为其数量绘制徽标,因此三星=3,索尼=7,以此类推,将绘制3个索尼徽标和7个三星徽标。 我想出了这样的办法 但是当然,所有这些都是为了每个数组条目,呼应出名称,所以我最终打印了5个三星,打印了5个索尼,等等。 如何使其使用 qty 数组的值而不是条目数?