为什么这两个Delphi代码块的行为不同?

时间:2019-02-23 23:10:07

标签: delphi syntax

在第一个代码块中注释的两个部分看似相同,但产生不同的结果(由于其他地方的问题)。我不明白他们有何不同。我唯一要更改的是注释掉第一部分(for循环)或第二部分(赋值行),并获得不同的结果。

var
  Amount: Integer;
  I: Integer;

begin
Amount := 3;

// This produces undesired results (**the for loop**)
for I := 0 to Amount-1 do
  CharDataBool[I] := CharToArray(CharDataText[I]);

// This works as expected (**the assignment lines**)
CharDataBool[0] := CharToArray(CharDataText[0]);
CharDataBool[1] := CharToArray(CharDataText[1]);
CharDataBool[2] := CharToArray(CharDataText[2]);

下面的代码有一个可疑的实践,并且在某种程度上是问题的根源,但我的问题是关于上面的代码。上面的问题仅在CharToArray函数留下未分配的假值时才显现出来,如下所示:

function CharToArray(Source: TCharDetails): TCharArray;
var
  X, Y: Integer;
begin
  SetLength(Result, Source.Width, 10);

  for Y := 0 to 9 do
    for X := 0 to Source.Width-1 do
      if Source.S[Y*Source.Width+X] = 'x' then
        Result[X,Y] := true
      else Result[X,Y] := false;     // Adding this solves the problem

end;

在没有进入“让值未知的问题真的很糟糕”的情况下,我只是想了解为什么问题在代码的第一部分中以(for循环)而不是(赋值行)表现出来?这三个赋值行与for循环有何不同?

可以在默认的VCL项目中通过Unit1复制以下内容

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TCharArray = array of array of boolean;

  TCharDetails = record
    S: String;
    Width: Integer;
  end;

var
  CharDataText: array of TCharDetails;
  CharDataBool: array of TCharArray;

var
  Form1: TForm1;

procedure Init;



implementation

{$R *.dfm}

function CharToArray(Source: TCharDetails): TCharArray;
var
  X, Y: Integer;
begin
  SetLength(Result, Source.Width, 10);

  for Y := 0 to 9 do
    for X := 0 to Source.Width-1 do
      if Source.S[Y*Source.Width+X] = 'x' then
        Result[X,Y] := true;

end;

procedure Init;
var
  Amount: Integer;
  I: Integer;

  X,Y: Integer;
  S1, S2: String;

begin
  Amount := 2;

  SetLength(CharDataText, Amount);
  SetLength(CharDataBool, Amount);

  ChardataText[0].Width := 10;
  ChardataText[0].S :=
//   1234567890
    '          ' +    // 0
    '  x       ' +    // 1
    ' xx       ' +    // 2
    '  x       ' +    // 3
    '  x       ' +    // 4
    '  x       ' +    // 5
    '  x       ' +    // 6
    '  x       ' +    // 7
    '  x       ' +    // 8
    ' xxx      ';

  ChardataText[1].Width := 10;
  ChardataText[1].S :=
//   1234567890
    'x         ' +    // 0
    '   xxxx   ' +    // 1
    '  x    x  ' +    // 2
    '       x  ' +    // 3
    '      x   ' +    // 4
    '     x    ' +    // 5
    '    x     ' +    // 6
    '   x      ' +    // 7
    '  x       ' +    // 8
    '  xxxxxx x';


  for I := 0 to Amount-1 do
    CharDataBool[I] := CharToArray(CharDataText[I]);   
  S1 := '';
  for Y := 0 to 9 do
    for X := 0 to 9 do
      S1 := S1 + CharDataBool[1,X,Y].ToString;

  CharDataBool[0] := CharToArray(CharDataText[0]);
  CharDataBool[1] := CharToArray(CharDataText[1]);    
  S2 := '';
  for Y := 0 to 9 do
    for X := 0 to 9 do
      S2 := S2 + CharDataBool[1,X,Y].ToString;

  // S1 != S2 ??
  ShowMessage(S1 + #13 + S2);      


end;

initialization

  Init;

end.

1 个答案:

答案 0 :(得分:4)

函数返回值是托管类型。 Result不能保证在进入函数后重新初始化。

在循环示例中,编译器优化了两次迭代之间隐式局部Result的重新初始化。这意味着该数组的先前内容仍然存在,必须清除。

作为一般规则,输入时始终初始化=清除托管函数结果。

在这种情况下,请首先在函数中调用SetLength(Result,0,0);


有关示例,请参见https://github.com/SpaceXar20/rest_api-mongo-p9

相关问题