代码之家  ›  专栏  ›  技术社区  ›  TopherCharles

帕斯卡在倒数而不是向上?所以维尔德

  •  3
  • TopherCharles  · 技术社区  · 7 年前

    http://rextester.com/OXRFB95557

    表上显示J号柜台向下而不是向上……你知道为什么吗?谢谢

    program NEACardTrick;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils,
      Math;
    
    type
      Tcards = array[1..21] of string;    
    var
       cards: Tcards = ('H A', 'H 2', 'H 3', 'H 4', 'H 5', 'H 6', 'H 7',
                 'S A', 'S 2', 'S 3', 'S 4', 'S 5', 'S 6', 'S 7',
                 'D A', 'D 2', 'D 3', 'D 4', 'D 5', 'D 6', 'D 7');
       shuffledCards:Tcards;
       i,j,y, x: integer;
    
    
    function get_cards(var cards: array of string): Tcards;    
    begin    
      y := 1;
      Repeat
        Randomize;
        x := RandomRange(1,21);
        If cards[x] <> 'Done' then
        begin
          shuffledCards[y] := cards[x];
          y := y + 1;
          cards[x] := 'Done';
        end    
      Until y >= 21;        
      result := shuffledCards;
    end;
    
    procedure PrintCards(var shuffledCards: Tcards);
    var
      j: integer;
    begin
      for j := 1 to 21 do
        writeln(shuffledCards[j]);
    end;
    
    begin    
      get_cards(cards);
      PrintCards(shuffledCards);
      readln;
    end.
    
    2 回复  |  直到 7 年前
        1
  •  6
  •   Tom Brunberg    7 年前

    你在Delphi7中关于 j: integer 变量输入 procedure PrintCards() 与调试器监视中显示的完全相同。但是,请放心, for 循环工作正常。

    在你的代码中,你已经给出 j 两个职责,1)作为循环控制,2)作为索引 shuffledCards[] 数组。

    编译器将您的Delphi代码转换为它能提供的高效(当然,是正确的)机器代码。安排一个循环,以便检测 ZF (零标志)作为循环终止条件,而不是与常量值进行显式比较,是提高效率的一种方法。因此,职责1)通过具有递减循环控制、寄存器 esi 在这种情况下(请参见下面的拆解)。

    对于第二个任务, ESI 寄存器不能使用,因为它计数方向错误。所以,另一个寄存器, ebx 用于任务2)。它被设置为指向数组第一个元素(索引为1的元素)的指针。然后在循环的每一圈 电子束外延 递增以指向下一个元素。

    下面是 PrintCards() 程序:

    Project2.dpr.38: begin
    0040876C 53               push ebx
    0040876D 56               push esi
    0040876E 57               push edi
    0040876F 8BF8             mov edi,eax
    
    Project2.dpr.39: for j := 1 to 21 do
    00408771 BE15000000       mov esi,$00000015    // Initialize loop control
    
    00408776 8BDF             mov ebx,edi          // set up pointer to array
    Project2.dpr.40: writeln(shuffledCards[j]);
    00408778 A160934000       mov eax,[$00409360]  // loop start
    0040877D 8B13             mov edx,[ebx]
    0040877F E8B4B8FFFF       call @WriteOLString
    00408784 E8CFA5FFFF       call @WriteLn
    00408789 E8B69EFFFF       call @_IOTest
    
    0040878E 83C304           add ebx,$04          // advance array element pointer
    Project2.dpr.39: for j := 1 to 21 do
    00408791 4E               dec esi              // decrement loop control
    00408792 75E4             jnz -$1c             // jump if not zero to loop start
    
    Project2.dpr.41: end;
    00408794 5F               pop edi
    00408795 5E               pop esi
    00408796 5B               pop ebx
    00408797 C3               ret
    

    在第39行放置一个断点,然后运行。在第39行停止时,调用cpu视图(view-debug windows-cpu或ctrl-alt-c)。然后单步(F8)并按照寄存器的更改进行操作,亲自查看

    调试程序监视 J 显示的值 ESI 因此,您会看到值从21下降到1(实际上,您可以看到最后一次之后出现的0 dec esi 执行)。

        2
  •  2
  •   David Heffernan    7 年前

    你的诊断不正确。索引变量在该循环中向上计数。

    如果不使用循环变量,编译器可能会优化循环计数器,使其按所选顺序运行。但是在循环中使用了索引变量,因此它必须增加。