2

I'm trying to clear a stringgrid but I'm getting an inconsistent access violation message which seems to appear after the last column has been cleared. Here is the code:

procedure ClearTable;
var
i:integer;
begin
  for i := 0 to 3 do
    begin
      frmHighscores.HighscoreTable.Cols[i].Clear;
    end;
end;

And here is the procedure that calls it:

procedure TfrmHighscores.sortbtnClick(Sender: TObject);
var
SortedScores :array of Thighscore;
i: integer;
Ascending:boolean;
begin
  ClearTable;
  Case sortRGP.ItemIndex of
   0: Ascending := False;
   1: Ascending :=True;
  end;
  AssignFile(HighScoreFile, 'HighScoreFile.DAT');
  Reset(HighScoreFile);
  If Filesize(Highscorefile) <= 1 then
    begin
      showmessage('There arent enough items to sort!');
    end;
  If Filesize(Highscorefile) > 1 then
    begin
      SetLength(SortedScores, Filesize(Highscorefile)-1);
      i:=0;
      While not eof(HighScoreFile) do
        begin
          Read(Highscorefile, Highscore[i+1]);
          sortedScores[i].Name := Highscore[i+1].Name;
          sortedScores[i].Score := Highscore[i+1].Score;
          sortedScores[i].DateSet := Highscore[i+1].DateSet;
          sortedScores[i].Difficulty := Highscore[i+1].Difficulty;
          inc(i);
        end;
    Closefile(highscorefile);
    Quicksort(SortedScores, Low(SortedScores), High(SortedScores)+1, Ascending);
    end;
end;

The error message when i try to run it is

Project C:\Users\Owner\V0.66\Project1.exe faulted with message: 'access
violation at 0x00401c51: write of address 0x00316572'. Process Stopped. Use Step or Run
to continue.

The error goes away when I change the code to this:

procedure ClearTable;
var
i:integer;
begin
  for i := 0 to 3 do
    begin
      showmessage('Attempting to clear Col ' +inttostr(i));
      frmHighscores.HighscoreTable.Cols[i].Clear;
      showmessage('Col ' +inttostr(i) + ' cleared successfully');
    end;
end;
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
jatsb
  • 21
  • 1

2 Answers2

4

This often comes from the incorrect allocation sizes (array). The last write process overrides the limits of the array. Which is not always immediately lead to a error. But, more or less important data will be overwritten.

We assume a record count of 15. then Filesize(Highscorefile) == 15 . The array should be [0.. .14]. But you generate only a length of 14 !

SetLength(SortedScores, Filesize(Highscorefile)-1); == 14.

So the array is [0..13] The last assignment overwrites data.

Mostly behind a array there is still space available and will not notice.

If parts of TSrings are overwritten and you try releasing (with strdispose) overwritten data, then there is a fault.

If new code is written,

showmessage('Attempting to clear Col ' +inttostr(i));

The memory will new organized with recompile and then this error comes at another place or not at all.

So replace
SetLength(SortedScores, Filesize(Highscorefile)-1);
with
SetLength(SortedScores, Filesize(Highscorefile));

And the error will be gone.

have a look at my answer https://stackoverflow.com/a/11888156/1322642

The OP how to get two different file with this procedure in deplhi
overwritting many of used data.
And when he has enough data overwritten, he gets a stack overflow error.

Community
  • 1
  • 1
moskito-x
  • 11,832
  • 5
  • 47
  • 60
0

frmHighscores is an instance of TfrmHighscores?

try making the procedure ClearTable private of TfrmHighscores and call:

HighscoreTable.Cols[i].Clear;

instead of

frmHighscores.HighscoreTable.Cols[i].Clear;

or you can try passing the form reference to the procedure:

procedure ClearTable(AFrmHighScores: TfrmHighscores);
var
i:integer;
begin
  for i := 0 to 3 do
    begin
      showmessage('Attempting to clear Col ' +inttostr(i));
      AFrmHighScores.HighscoreTable.Cols[i].Clear;
      showmessage('Col ' +inttostr(i) + ' cleared successfully');
    end;
end;

calling it in code:

ClearTable(Self);
Agustin Seifert
  • 1,938
  • 1
  • 16
  • 29