遇到了在我的随机数数组排序程序中找到无效内存访问的问题。

huangapple go评论50阅读模式
英文:

Having trouble finding the invalid memory access in my random number array sorting program

问题

在你的代码中,似乎有一些问题。不过你提到的具体错误信息是 "Access violation executing location 0x00000064",这通常表示访问了无效的内存位置。我会检查你的代码以寻找潜在的问题。

首先,我注意到在 sortList 过程中,你使用了寄存器 edx,但没有在使用之前清除它的值。确保在使用 edx 之前将其清零。

另外,在 displayListDescending 过程中,你对 esi 进行了递减操作,但没有检查是否越界。请确保 esi 不会越界到数组之外。

最后,确保你的数组足够大来容纳 request 中指定的数量,否则可能会导致访问无效内存。

请检查这些问题,看看是否有助于解决你的异常问题。如果问题仍然存在,你可能需要更详细地调试以找到问题的确切位置。

英文:

I am coding this for an assignment, where I am required to make an array in MASM and assign it random numbers given a number input. I am past the selection sort part of my assignment, and I am having trouble finding out where I am not accessing the write memory. The error code that I get is:

> Exception thrown at 0x00000064 in Project.exe: 0xC0000005: Access violation executing location 0x00000064.

And here is the rest of my code:

INCLUDE Irvine32.inc

.data
    instructions BYTE "This program generates random numbers in the range [100 .. 999], displays the original list, sorts the list, and calculates the median value. Finally, it displays the list sorted in descending order.",0
    unsorted    BYTE "The unsorted random numbers:",0
    median      BYTE "The median is ",0
    sorted      BYTE "The sorted list:",0
    prompt      BYTE "How many numbers should be generated? [10 .. 200]: ",0
    invalid     BYTE "Invalid input",0
    newline     BYTE 0DH, 0AH, 0
    spaceBar    BYTE " ", 0
    array       DWORD 200 DUP(?)
    request     DWORD ?
    medianValue DWORD ?

.code
    main PROC
          call introduction
          call getData
          call generateRandomNumbers
          call displayList
          call calculateMedian
          call displayMedian
          call sortList
          call displayListDescending

          exit
     main ENDP

     introduction PROC
          mov edx, OFFSET instructions
          call WriteString
          call Crlf
          ret
     introduction ENDP

     getData PROC
          mov edx, OFFSET prompt
          call WriteString
          call ReadInt
          cmp eax, 10
          jl invalidInput
          cmp eax, 200
          jg invalidInput
          mov [request], eax
          ret

          invalidInput:
          mov edx, OFFSET invalid
          call WriteString
          call Crlf
          jmp getData
     getData ENDP

     generateRandomNumbers PROC
          mov ecx, [request]
          mov esi, OFFSET array
          generateLoop:
               call RandomRange ; Generates random number in the range [0, 899]
               add eax, 100 ; Adjust the range to [100, 999]
               mov [esi], eax
               add esi, 4
               loop generateLoop
          ret
     generateRandomNumbers ENDP

     displayList PROC
          mov edx, OFFSET unsorted
          call WriteString
          call Crlf
          mov edx, OFFSET newline
          call WriteString
          mov ecx, [request]
          mov esi, OFFSET array
          displayLoop:
          mov eax, [esi]
          call WriteInt
          mov edx, OFFSET spaceBar
          call WriteString
          add esi, 4
          loop displayLoop
          call Crlf
          ret
     displayList ENDP

     calculateMedian PROC
          mov ecx, [request]
          shr ecx, 1
          mov esi, OFFSET array
          mov eax, [esi+ecx*4]
          mov [medianValue], eax
          ret
     calculateMedian ENDP

     displayMedian PROC
          mov edx, OFFSET median
          call WriteString
          call Crlf
          mov edx, OFFSET newline
          call WriteString
          mov edx, [medianValue]
          call WriteInt
          call Crlf
          ret
     displayMedian ENDP
     
    sortList PROC
          mov ecx, [request]
          mov esi, OFFSET array
          mov ebx, OFFSET array
          mov edi, ecx

          sortLoop:
               xor edx, edx
               mov eax, [esi]
               innerLoop:
                    add ebx, 4
                    cmp ebx, edi
                    jge skipExchange
                    mov edx, [ebx]
                    cmp edx, 100
                    jge skipExchange
                    mov eax, edx
                    mov edi, ebx
               skipExchange:
                    loop innerLoop

               cmp esi, edi
               je skipSwap

               push eax
               push [esi]
               call exchangeElements
               skipSwap:
                    add esi, 4
                    cmp edx, 0
                    jne sortLoop
               
               ret

   sortList ENDP

   displayListDescending PROC
          mov edx, OFFSET newline
          call WriteString
          mov ecx, [request]
          mov esi, OFFSET array

          mov eax, ecx           ; Store the value of ecx in eax
          dec eax                ; Decrement eax to get (ecx-1)
          mov ebx, 4
          mul ebx
          shl eax, 2             ; Multiply by 4 (shift left by 2)
          add esi, eax           ; Add the offset to the base address of the array

          displayLoop:
               mov eax, [esi]
               call WriteInt
               mov edx, OFFSET spaceBar
               call WriteString
               sub esi, 4
               loop displayLoop

          call Crlf
          ret
    displayListDescending ENDP



    exchangeElements PROC
          push edx
          mov edx, [esp+12]
          mov ecx, [esp+8]
          mov [esp+12], ecx
          mov [esp+8], edx
          pop edx
          ret
     exchangeElements ENDP

END main

My best guess where the exception is being thrown is in the displayListDescending procedure. I have tried to simplify the registers and have even tried to keep track of what ESI is even tracking.
I'd appreciate any help I possibly can get.

答案1

得分: 1

The exception

异常

我最好的猜测是异常被抛出的地方在 displayListDescending 过程中。

确实,在这里,您的程序在数组之外的内存中读取数据!计算数组中最后一个元素的偏移错误地将索引乘以4 重复两次

mov  ecx, [request]
mov  esi, OFFSET array
mov  eax, ecx
dec  eax
mov  ebx, 4             <<<< 1st x 4
mul  ebx
shl  eax, 2             <<<< 2nd x 4
add  esi, eax

解决方法之一是写成:

mov  ecx, [request]
lea  esi, [array + ecx * 4 - 4]

Random numbers

随机数

generateRandomNumbers PROC
   mov  ecx, [request]
   mov  esi, OFFSET array
 generateLoop:
   call RandomRange ; 在范围[0, 899]内生成随机数
   add  eax, 100    ; 调整范围为[100, 999]
   mov  [esi], eax
   add  esi, 4
   loop generateLoop
   ret
generateRandomNumbers ENDP

您没有在范围[0, 899]内生成随机数。要实现这一点,您需要在 call RandomRange 前将 ECX 设置为 900。但由于这会与当前的循环计数器冲突,您需要使用另一个寄存器来控制循环:

generateRandomNumbers PROC
   mov  edi, [request]
   mov  esi, OFFSET array
  generateLoop:
   mov  ecx, 900
   call RandomRange ; 在范围[0, 899]内生成随机数
   add  eax, 100    ; 调整范围为[100, 999]
   mov  [esi], eax
   add  esi, 4
   dec  edi
   jnz  generateLoop
  ret
generateRandomNumbers ENDP

The median

中位数

mov edx, [medianValue]
call WriteInt

传递给 WriteInt 的输入位于 EAX 中。

The selection sort

选择排序

sortList 及其附带的 exchangeElements 过程无法挽救。它们包含了许多难以解释的操作,这也使得很难确定它是否真正是选择排序,而不是其他排序方法。

我编写了这个选择排序算法,附带可视化演示,以便您了解它的工作原理。尽管它使用了16位寄存器,但将其移植到32位应该不难。

英文:

The exception

> My best guess where the exception is being thrown is in the displayListDescending procedure.

Indeed, that is where your program reads from memory outside of the array! The calculation of the offset to the last element in the array is erroneously multiplying the index by 4 doing it twice.

> mov ecx, [request]
> mov esi, OFFSET array
> mov eax, ecx
> dec eax
> mov ebx, 4 <<<< 1st x 4
> mul ebx
> shl eax, 2 <<<< 2nd x 4
> add esi, eax

One way to solve it is to write:

mov  ecx, [request]
lea  esi, [array + ecx * 4 - 4]

Random numbers

> generateRandomNumbers PROC
> mov ecx, [request]
> mov esi, OFFSET array
> generateLoop:
> call RandomRange ; Generates random number in the range [0, 899]
> add eax, 100 ; Adjust the range to [100, 999]
> mov [esi], eax
> add esi, 4
> loop generateLoop
> ret
> generateRandomNumbers ENDP

You are not generating a random number in the range [0,899]. For that to happen you need to set ECX=900 before call RandomRange. But since that would clash with the current loop counter, you need to use another register to control the loop:

generateRandomNumbers PROC
   mov  edi, [request]
   mov  esi, OFFSET array
  generateLoop:
   mov  ecx, 900
   call RandomRange ; Generates random number in the range [0, 899]
   add  eax, 100    ; Adjust the range to [100, 999]
   mov  [esi], eax
   add  esi, 4
   dec  edi
   jnz  generateLoop
  ret
generateRandomNumbers ENDP

The median

> mov edx, [medianValue]
> call WriteInt

The input to WriteInt goes in EAX.

The selection sort

The sortList and its accompanying exchangeElements procedures are not salvageable. They contain a lot of inexplicable operations that also make it hard to even find out if it is an actual selection sort and not some other sorting method.
I wrote this selection sort algorithm with a visual run-through so you can understand how it works. Although it uses 16-bit registers, porting it to 32-bit should not be difficult.

答案2

得分: 0

exchangeElements 可能需要一个 "ret 8",因为在调用它之前你压入了两个双字。

英文:

exchangeElements probably needs a "ret 8" since you push two dwords before calling it.

huangapple
  • 本文由 发表于 2023年6月1日 05:22:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76377390.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定