Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi sporadisch auftretende Nil-Pointer (https://www.delphipraxis.net/55466-sporadisch-auftretende-nil-pointer.html)

DGL-luke 21. Okt 2005 14:12


sporadisch auftretende Nil-Pointer
 
Liste der Anhänge anzeigen (Anzahl: 2)
Ich hab hier eine kleine Plotter-Klasse geschrieben. Diese nimmt zweidimensional Daten entgegen und kann diesesowohl absolut als auch relativ als Säulen- oder Liniendiagramm darstellen. Eine kleine Beispielausgabe hab ich angehängt ;)

In der Zeichenprozedur wirft es nun, nahezu zufällig (in etwa 50% der aufrufe), AVs mit "read from 000000000", beim Zugriff auf ein dynamisches array, dessen grenzen eigentlich absolut sicher sind. Auch kommt zwischen durch immer mal ein
Zitat:

---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt PCoins.exe ist eine Exception der Klasse EInvalidOperation mit der Meldung 'Leinwand/Bild erlaubt kein Zeichnen' aufgetreten.
Und das kann ich mir einfach nicht erklären.... Im Anhang die komplette unit, hier die zeichenprozedur:

Delphi-Quellcode:
function TPlotter.DrawGraph(dimensions:TPoint;scale:single;range:TIntArray):TBitMap32;
var i,k:integer;
    P:TPoint;
    mult:single;
    YOffSet:integer;
    value:single;
begin

YOffSet:=3;

//init
result:=TBitmap32.Create;

result.Width := dimensions.X;
result.Height := dimensions.Y;

if updating or (length(fdata) < 1) then exit;

dimensions.X := length(fdata) * length(fdata[1]) *  XOffSet;
result.Width := dimensions.X;

result.Canvas.Brush.Color := clwhite;
result.Canvas.Rectangle(0,0,dimensions.X,dimensions.Y);

result.Canvas.Pen.Color  := clblack;                     //hier kommt das mit der leinwand.
result.Canvas.Brush.Style := bsclear;

//param checking
range[0]:=Max(low(fData),range[0]);
range[1]:=Min(high(fData),range[1]);

if fMaxValue <> 0 then
mult := (dimensions.Y -10) / (fMaxValue + YOffSet) * scale
else mult := 1;

//drawing

drawscale(mult,-YOffSet,10,result);

result.Canvas.Pen.Width:=5;

case fstyle of
 sColumns:
  for i := range[0] to range[1] do
   for k:= 0 to length(fData[i])-1 do
     begin
       result.Canvas.Pen.Color := fColors[k];
       P.X := round((i*  result.Width / range[1] - range[0] / 2) + k*4 + 20);

       value := fdata[i,k];                            // manchmal hier....
       if (drawmode = dmChanges) then
        value := fdata[i,k] - fdata[Max(i-1,0),k];     // und manschmal da....

       P.Y := round(value*mult) ;

       result.Canvas.MoveTo(P.X,result.Height - 1 - round(YOffSet * mult));
       result.Canvas.LineTo(P.X,result.Height - P.Y -round(YOffSet * mult)-1);
    end;
 sLines:
   for k:= 0 to length(fData[0])-1 do
    for i := range[0] to range[1] do
      begin
       result.Canvas.Pen.Color := fColors[k];
       P.X := round((i*  result.Width / range[1] - range[0] / 2) + k*4 + 20);

       value := fdata[i,k];                       //hier unten natürlich auch.
       if (drawmode = dmChanges) then
        value := fdata[i,k] - fdata[Max(i-1,0),k];

       P.Y := round(value*mult) ;


       if i=0 then
         result.Canvas.MoveTo(0, result.Height - P.Y -round(YOffSet * mult)-1);
       result.Canvas.LineTo(P.X,result.Height - P.Y -round(YOffSet * mult)-1);
      end;
 end;

drawlegend(rect(0,0,100,300),result);
end;

jim_raynor 22. Okt 2005 18:02

Re: sporadisch auftretende Nil-Pointer
 
Mal Bereichsprüfung in den Projekt-Optionen aktiviert. Eventuell schreibst du irgendwo über Array-Grenzen hinaus ...

DGL-luke 22. Okt 2005 19:37

Re: sporadisch auftretende Nil-Pointer
 
ja, das war exakt das problem. allerdings in einer dimension, in die ich nicht gleich geschaut hab ;). habs jetzt rausgekriegt.

So alloziiere ich mein array:
Delphi-Quellcode:
procedure TPlotter.AddData(data: array of single);
var i,newlength:integer;
    max:single;
begin
//memory management
if length(fdata) <= fOccupied then
 begin
   newlength:=round(length(fdata)*1.72)+1;
   setlength(fdata,newlength);
 end;
//value assignment
fOccupied:=fOccupied+1;
setlength(fData[fOccupied-1],IfThen((fOccupied - 1 = 0),length(data),length(fdata[0])));
for i := 0 to high(fData[fOccupied-1]) do
 begin
   fData[fOccupied-1,i]:=data[i];
   fMaxValue:=math.max(fMaxValue,data[i]);
 end;
end;
Ich vergrößere mein array also immer um 172% und in der zweiten dimension wird es erst alloziiert, wenn ein wert zugewiesen wird.

und in meiner glorreichen Intelligenz hab ich natürlich beim überprüfen der array-grenzen mist gebaut(ein ausschnitt aus der funktion, die im ersten post gepostet ist):

Delphi-Quellcode:
//param checking
range[0]:=Max(low(fData),range[0]);
range[1]:=Min(high(fData),range[1]);
das high(fData) muss natürlich fOccupied-1 heissen. :roll:

Vielen Dank für ihre geschätzte Aufmerksamkeit. :zwinker:


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:32 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz