Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do these two Delphi code blocks behave different?

Tags:

syntax

delphi

The two sections commented in the first code block are seemingly identical yet yield different result (due to problems elsewhere). I do not understand how they are different. The only thing I change is to comment out the first part (the for loop) or the second part (the assignment lines) and get different results.

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]);

The code below has questionable practice, and in a way is the source of the problem, but my question is about the code above. The problem above only manifests if the CharToArray function leaves false unassigned as can be seen here:

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;

Without going into "leaving values unknown is real bad" which it is, I just want to understand why the problem manifests with (the for loop) and not with (the assigment lines) in the first section of code? How are the three assignment lines different from the for loop?

Below can be copied over Unit1 in default VCL project

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.
like image 619
Doege Avatar asked Jul 26 '26 13:07

Doege


1 Answers

The function return value is a managed type. The Result is not guaranteed to be re-initialized upon entry to the function.

In the loop example, the compiler optimizes away the implicit local Result re-initialization between the iterations. That means that the previous content of the array is still present and must be cleared.

As a general rule, always initialize=clear managed function results upon entry.

In this case, call SetLength(Result,0,0); first thing in the function.


See Do I need to setLength a dynamic array on initialization? for an example.

like image 193
LU RD Avatar answered Jul 28 '26 06:07

LU RD