Почему эти два блока кода Delphi ведут себя по-разному? - PullRequest
0 голосов
/ 24 февраля 2019

Два раздела, прокомментированные в первом блоке кода, кажутся идентичными, но дают различный результат (из-за проблем в другом месте).Я не понимаю, чем они отличаются.Единственное, что я изменяю, это закомментирую первую часть (цикл 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 оставляет false неназначенным, как это можно увидеть здесь:

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?

Ниже можно скопировать на Unit1 в проекте VCL по умолчанию

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 голосов
/ 24 февраля 2019

Возвращаемое значение функции - управляемый тип.Result не гарантируется повторная инициализация при входе в функцию.

В примере цикла компилятор оптимизирует неявную локальную Result повторную инициализацию между итерациями.Это означает, что предыдущее содержимое массива все еще присутствует и должно быть очищено.

Как правило, всегда инициализируйте = очищать результаты управляемой функции при входе.

В этом случае вызовите SetLength(Result,0,0); первое, что есть в функции.


См. Нужно ли устанавливать длину динамического массива при инициализации? для примера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...