1

I have this for loop pair in a Delphi 6 procedure:

procedure TNumbers.CleanTable(Sender: TObject);
var
  Index: integer;
  JIndex: integer;
  IEND, JEND: integer;
  Obj: TObject;
begin
  IEND := length(Correspondence);
  JEND := length(Correspondence[0]);
  for Index := 1 to IEND-1 do
  begin
    for JIndex := 1 to JEND -1 do
    begin
      obj := SearchForTagID(Correspondence[Index,JIndex], Sender);
      if obj = nil then continue;
      if obj is TComponent then
      begin
        if TComponent(Obj).Tag = Correspondence[Index, JIndex] then 
        // make sure search was successful
        begin
          VoidCaption(obj);
        end;
      end;
    end;
  end;
end;

I added the IEND and JEnd variables rather than call length directly so I could keep an eye on the result.

Now the crux of the problem is that the control variables of the loops are not properly initialized. The index and JIndex should both start at 1 (to skip the leading edges of the array, which contain titles, not data). However, what I get is Index and Jindex at IEND AND JEND right from the start.

I tried commenting out the entire block, keeping only the loops; I even commented out the obj declaration, in case that might affect the loop. NOTHING changed. I still had loop initialization wrong.

Has anyone ever seen this before? In my 40 years of programming, it's the first time I ever see something like this, and I made my fair share of for loop errors!

For lack of a solution, I replaced the for loops with this code, which works:

procedure TNumbers.CleanTable(Sender:TObject);
var
  Index: integer;
  JIndex: integer;
  IEND, JEND: integer;
  Obj: TObject;
begin
  IEND := length(Correspondence);
  JEND := length(Correspondence[0]);
  Index := 1;
  while Index < IEND do
  begin
    JIndex := 1;
    while JIndex < JEND do
    begin
      obj := SearchForTagID(Correspondence[Index,JIndex], Sender);
      if obj = nil then continue;
      if obj is TComponent then
      begin
        if TComponent(Obj).Tag = Correspondence[Index,JIndex] then 
        // make sure search was successful
        begin
          VoidCaption(obj);
        end;
      end;
      inc(JIndex);
    end; // JIndex while end
    inc(Index);
  end; // IIndex while end
end;

If I can't trust the compiler with such a simple loop system, I'm in deep trouble.

Any suggestion as to the cause?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    Your conclusion regarding trusting loops is just a misunderstanding of what the debugger is showing about for loop, explained in [this post](https://stackoverflow.com/a/35478474/2292722). – Tom Brunberg Mar 19 '18 at 05:45
  • You did not say what original problem (with the first code) you had that got you to look closely at the loop control variables in the first place. It puzzles me that your second code would work any better for the actual task. Perhaps you should run the indexes from highest value down to 1 instead, in case the number of items is decreased in `VoidCaption(obj)`? – Tom Brunberg Mar 19 '18 at 06:10

1 Answers1

0

Your are indeed making confusion with your indexes. The JIndex is clearly incorrect, since it is computed only once for Index=0 iteration.

Don't use while, but two nested for loops:

procedure TNumbers.CleanTable(Sender:TObject);
var
  i, j: integer;
  obj: TObject;
begin
  for i := 0 to high(Correspondence) do
    for j := 0 to high(Correspondence[i]) do begin
      obj := SearchForTagID(Correspondence[i,j], Sender);
      if (obj <> nil) and (obj is TComponent) then
        if TComponent(Obj).Tag = Correspondence[i,j] then
          // make sure search was successful
          VoidCaption(obj);
    end;
end;

Now the code is much more readeable.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159