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

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

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:

  1. INCLUDE Irvine32.inc
  2. .data
  3. 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
  4. unsorted BYTE "The unsorted random numbers:",0
  5. median BYTE "The median is ",0
  6. sorted BYTE "The sorted list:",0
  7. prompt BYTE "How many numbers should be generated? [10 .. 200]: ",0
  8. invalid BYTE "Invalid input",0
  9. newline BYTE 0DH, 0AH, 0
  10. spaceBar BYTE " ", 0
  11. array DWORD 200 DUP(?)
  12. request DWORD ?
  13. medianValue DWORD ?
  14. .code
  15. main PROC
  16. call introduction
  17. call getData
  18. call generateRandomNumbers
  19. call displayList
  20. call calculateMedian
  21. call displayMedian
  22. call sortList
  23. call displayListDescending
  24. exit
  25. main ENDP
  26. introduction PROC
  27. mov edx, OFFSET instructions
  28. call WriteString
  29. call Crlf
  30. ret
  31. introduction ENDP
  32. getData PROC
  33. mov edx, OFFSET prompt
  34. call WriteString
  35. call ReadInt
  36. cmp eax, 10
  37. jl invalidInput
  38. cmp eax, 200
  39. jg invalidInput
  40. mov [request], eax
  41. ret
  42. invalidInput:
  43. mov edx, OFFSET invalid
  44. call WriteString
  45. call Crlf
  46. jmp getData
  47. getData ENDP
  48. generateRandomNumbers PROC
  49. mov ecx, [request]
  50. mov esi, OFFSET array
  51. generateLoop:
  52. call RandomRange ; Generates random number in the range [0, 899]
  53. add eax, 100 ; Adjust the range to [100, 999]
  54. mov [esi], eax
  55. add esi, 4
  56. loop generateLoop
  57. ret
  58. generateRandomNumbers ENDP
  59. displayList PROC
  60. mov edx, OFFSET unsorted
  61. call WriteString
  62. call Crlf
  63. mov edx, OFFSET newline
  64. call WriteString
  65. mov ecx, [request]
  66. mov esi, OFFSET array
  67. displayLoop:
  68. mov eax, [esi]
  69. call WriteInt
  70. mov edx, OFFSET spaceBar
  71. call WriteString
  72. add esi, 4
  73. loop displayLoop
  74. call Crlf
  75. ret
  76. displayList ENDP
  77. calculateMedian PROC
  78. mov ecx, [request]
  79. shr ecx, 1
  80. mov esi, OFFSET array
  81. mov eax, [esi+ecx*4]
  82. mov [medianValue], eax
  83. ret
  84. calculateMedian ENDP
  85. displayMedian PROC
  86. mov edx, OFFSET median
  87. call WriteString
  88. call Crlf
  89. mov edx, OFFSET newline
  90. call WriteString
  91. mov edx, [medianValue]
  92. call WriteInt
  93. call Crlf
  94. ret
  95. displayMedian ENDP
  96. sortList PROC
  97. mov ecx, [request]
  98. mov esi, OFFSET array
  99. mov ebx, OFFSET array
  100. mov edi, ecx
  101. sortLoop:
  102. xor edx, edx
  103. mov eax, [esi]
  104. innerLoop:
  105. add ebx, 4
  106. cmp ebx, edi
  107. jge skipExchange
  108. mov edx, [ebx]
  109. cmp edx, 100
  110. jge skipExchange
  111. mov eax, edx
  112. mov edi, ebx
  113. skipExchange:
  114. loop innerLoop
  115. cmp esi, edi
  116. je skipSwap
  117. push eax
  118. push [esi]
  119. call exchangeElements
  120. skipSwap:
  121. add esi, 4
  122. cmp edx, 0
  123. jne sortLoop
  124. ret
  125. sortList ENDP
  126. displayListDescending PROC
  127. mov edx, OFFSET newline
  128. call WriteString
  129. mov ecx, [request]
  130. mov esi, OFFSET array
  131. mov eax, ecx ; Store the value of ecx in eax
  132. dec eax ; Decrement eax to get (ecx-1)
  133. mov ebx, 4
  134. mul ebx
  135. shl eax, 2 ; Multiply by 4 (shift left by 2)
  136. add esi, eax ; Add the offset to the base address of the array
  137. displayLoop:
  138. mov eax, [esi]
  139. call WriteInt
  140. mov edx, OFFSET spaceBar
  141. call WriteString
  142. sub esi, 4
  143. loop displayLoop
  144. call Crlf
  145. ret
  146. displayListDescending ENDP
  147. exchangeElements PROC
  148. push edx
  149. mov edx, [esp+12]
  150. mov ecx, [esp+8]
  151. mov [esp+12], ecx
  152. mov [esp+8], edx
  153. pop edx
  154. ret
  155. exchangeElements ENDP
  156. 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 重复两次

  1. mov ecx, [request]
  2. mov esi, OFFSET array
  3. mov eax, ecx
  4. dec eax
  5. mov ebx, 4 <<<< 1st x 4
  6. mul ebx
  7. shl eax, 2 <<<< 2nd x 4
  8. add esi, eax

解决方法之一是写成:

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

Random numbers

随机数

  1. generateRandomNumbers PROC
  2. mov ecx, [request]
  3. mov esi, OFFSET array
  4. generateLoop:
  5. call RandomRange ; 在范围[0, 899]内生成随机数
  6. add eax, 100 ; 调整范围为[100, 999]
  7. mov [esi], eax
  8. add esi, 4
  9. loop generateLoop
  10. ret
  11. generateRandomNumbers ENDP

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

  1. generateRandomNumbers PROC
  2. mov edi, [request]
  3. mov esi, OFFSET array
  4. generateLoop:
  5. mov ecx, 900
  6. call RandomRange ; 在范围[0, 899]内生成随机数
  7. add eax, 100 ; 调整范围为[100, 999]
  8. mov [esi], eax
  9. add esi, 4
  10. dec edi
  11. jnz generateLoop
  12. ret
  13. generateRandomNumbers ENDP

The median

中位数

  1. mov edx, [medianValue]
  2. 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:

  1. mov ecx, [request]
  2. 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:

  1. generateRandomNumbers PROC
  2. mov edi, [request]
  3. mov esi, OFFSET array
  4. generateLoop:
  5. mov ecx, 900
  6. call RandomRange ; Generates random number in the range [0, 899]
  7. add eax, 100 ; Adjust the range to [100, 999]
  8. mov [esi], eax
  9. add esi, 4
  10. dec edi
  11. jnz generateLoop
  12. ret
  13. 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:

确定