Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Problem mit Pointern (https://www.delphipraxis.net/135213-problem-mit-pointern.html)

Sascha 6. Jun 2009 21:07


Problem mit Pointern
 
Delphi-Quellcode:
  PKnoten = ^TKnoten;

  TKnoten = record // Record für Knoten
  public
   pSuper ,pBit0, pBit1: PKnoten;
   bSuper: boolean;
   iHaeufigkeit: int64;
   cBuchstabe: char;
  end;

 ...

var
 aKnoten: array of TKnoten;
Delphi-Quellcode:
 ShowMessage(IntToStr(aKnoten[4].pBit0^.iHaeufigkeit));
 ShowMessage(IntToStr(aKnoten[4].pBit0^.iHaeufigkeit));
Bei der ersten Message kommt 3 raus (was richtig ist), beim zweiten mal jedoch 0.
Die Beiden Zeilen stehen genau hintereinander. Nur wo ist da der Fehler das das passiert?

(Delphi2005)

Dezipaitor 6. Jun 2009 23:38

Re: Problem mit Pointern
 
Meine Glaskugel sagt mir, dass du die Zeiger nicht mit New initialisiert hast.

New(aKnoten[4].pBit0);

Muetze1 6. Jun 2009 23:41

Re: Problem mit Pointern
 
Mein Verstand sagt mir, dass Dezipaitor .iHaeufigkeit noch entfernen wollte. Mein Verstand war langsamer als seine Finger...

Meine Glaskugel sagt mir, dass du dir u.a. Pointer auf Array Elemente von aKnoten vermerkt, u.a. in anderen Knoten der Liste. Leider aber auch zwischendurch die Liste verlängerst/verkürzt. Dabei wiederrum werden aber u.U. alle Zeiger ungültig in der Liste, da ein dynamisches Array frei im Speicher bewegt wird bei der Realloziierung, abhängig davon wo Speicher zur Verfügung steht.

SirThornberry 6. Jun 2009 23:41

Re: Problem mit Pointern
 
bei 2 mal der exakt gleichen Anweisung hintereinander passieren verschiedene Dinge? Wenn dem so ist so genügt der zusammgengekürzte Quelltext den du uns offenbart hast nicht aus um den Fehler zu finden.

thkerkmann 7. Jun 2009 08:47

Re: Problem mit Pointern
 
Hi,

ich würde es vermeiden, eine Verkettete Listen Struktur in dynamischen Arrays abzulegen. Das widerspricht sich für mich irgendwie. Hier wird mit New() und Dispose() gearbeitet. Wenn Du in dynamischen Arrays arbeiten willst, verwende keine Zeiger, sondern Indices um auf andere Elemente in dem Array zu verweisen. Das gehört wieder zusammen.

Gruss

Sascha 7. Jun 2009 09:33

Re: Problem mit Pointern
 
Delphi-Quellcode:
var
  Form1: TForm1;
  aKnoten: array of TKnoten;

const
  cBuchs: array[0..3] of char = ('c', 'a', 'b', 'd');
  iBuchs: array[0..3] of int64 = (6, 5, 2, 3);

implementation
{$R *.dfm}
{$O-}

procedure TForm1.Button1Click(Sender: TObject);
var
 i, x: int64; // x = Length aKnoten
 Mi0, Mi1: TMinInd;
 Point: PKnoten;
 bitcode: string;
begin
 // anderweitige Initialisierung
 x := length(iBuchs);
 SetLength(aKnoten, x);
 // anderweitige Initialisierung -> Complete

 // Komplettinitialisierung des verwendeten Arrays
 i := 0;
 repeat
  aKnoten[i].cBuchstabe := cbuchs[i];
  aKnoten[i].iHaeufigkeit := ibuchs[i];
  aKnoten[i].pSuper := nil;
  aKnoten[i].pBit0 := nil;
  aKnoten[i].pBit1 := nil;
  inc(i);
 until (i = x);
 // Komplettinitialisierung des verwendeten Arrays -> Complete

 // Damit Schleife nicht gleich abbricht
 // Danach Baumerstellung
 mi1.haeuf := high(int64) - 1;
 while mi1.haeuf <> high(int64) do
 begin
  mi1.index := -1;
  mi1.haeuf := high(int64);
  mi0.index := -1;
  mi0.haeuf := high(int64);
  i := -1;
  repeat
   inc(i);
   if (aKnoten[i].iHaeufigkeit < mi1.haeuf) and
    (aKnoten[i].pSuper = nil) then
   begin
    mi1.index := mi0.index;
    mi1.haeuf := mi0.haeuf;
    mi0.index := i;
    mi0.haeuf := aKnoten[i].iHaeufigkeit;
   end;
  until (i = x - 1);
  Memo1.Lines.Add('indexi: ' + IntToStr(i));
  Memo1.Lines.Add('index0: ' + IntToStr(mi0.index));
  Memo1.Lines.Add('haeuf0: ' + IntToStr(mi0.haeuf));
  Memo1.Lines.Add('index1: ' + IntToStr(mi1.index));
  Memo1.Lines.Add('haeuf1: ' + IntToStr(mi1.haeuf));
  Memo1.Lines.Add('------------');


  // neuen Knoten hinzufügen
  if mi1.index <> -1 then
  begin
   inc(x);
   SetLength(aKnoten, x);
   aKnoten[x - 1].pSuper := nil;
   aKnoten[x - 1].iHaeufigkeit := mi1.haeuf
     + mi0.haeuf;
   aKnoten[x - 1].pBit0 := @aKnoten[mi0.index];
   aKnoten[x - 1].pBit1 := @aKnoten[mi1.index];
   aKnoten[x - 1].cBuchstabe := #0;

   aKnoten[mi0.index].pSuper := @aKnoten[x - 1];
   aKnoten[mi0.index].bSuper := false;
   aKnoten[mi1.index].pSuper := @aKnoten[x - 1];
   aKnoten[mi1.index].bSuper := true;
  end;
  // neuen Knoten hinzufügen -> Complete
 end;

 // BitCode auslesen!
 i := 0;
{
  repeat
  if (aKnoten[i].pBit0 = nil) and (aKnoten[i].pBit1 = nil) then
  begin
   // Hier Code zum BitCode auslesen schreiben!
   bitcode := '';

   if aKnoten[i].bSuper then bitcode := '1' + bitcode
     else bitcode := '0' + bitcode;

   Point := aKnoten[i].pSuper;

   while (Point^.pSuper <> nil) do
   begin
    Point := Point^.pSuper;
    if Point.bSuper then bitcode := '1' + bitcode
     else bitcode := '0' + bitcode;
   end;

   Memo1.Lines.Add('BitCode für *' +
     aKnoten[i].cBuchstabe + '* =' + bitcode);
  end;
  inc(i);
 until i = length(aKnoten);
}
 Point := aKnoten[4].pBit0;
 ShowMessage(IntToStr(aKnoten[4].pBit0^.iHaeufigkeit));
 ShowMessage(IntToStr(aKnoten[4].pBit0^.iHaeufigkeit));
{
 point := aKnoten[3].pSuper;
 while (point^.pSuper <> nil) do
 begin
  ShowMessage(IntToStr(point^.iHaeufigkeit));
  point := point^.pSuper;
 end;
}

 // BitCode auslesen! -> Complete
end;


end.

SirThornberry 7. Jun 2009 09:58

Re: Problem mit Pointern
 
Muetze1 hat den Fehler richtig vermutet gehabt:
Du holst dir die Adresse eines Arrayelementes und speicherst/merkst dir diese
Delphi-Quellcode:
aKnoten[mi0.index].pSuper := @aKnoten[x - 1];
Wenn du dann allerdings mit
Delphi-Quellcode:
SetLength(aKnoten, x);
die Größe des Arrays änderst wird unter umständen das Array wo anders in den Speicher hinkopiert (weil an der aktuellen Position nicht genug Platz ist zum vergrößern).
Somit hast du in .pSuper eine alte Adresse stehen die nicht mehr aktuell ist weil das Array jetzt wo ganz anders im Speicher liegt.

Sascha 7. Jun 2009 10:37

Re: Problem mit Pointern
 
naja nur beim ersten aufruf kommt das richtige ergebnis.. in der zeile danach nicht..
und unter Delphi 2008 läuft es ohne fehler.
Unter Delphi2005 bekomme ich den Fehler...

Blup 8. Jun 2009 08:31

Re: Problem mit Pointern
 
Zitat:

Zitat von Sascha
naja nur beim ersten aufruf kommt das richtige ergebnis.. in der zeile danach nicht..
und unter Delphi 2008 läuft es ohne fehler.
Unter Delphi2005 bekomme ich den Fehler...

Wie viel Speicher nach dem Array noch frei ist, um es zu vergrößeren, ist nun mal von vielen Faktoren abhängig.
Nach jeder Vergrößerung können alle Pointer auf Elemente dieses Arrays ungültig werden.
Das ist im Prinzip in jeder Delphiversion so.

Verwende statt dessen ein TList-Object und erstelle die Knoten mit New und gib diese mit Dispose wieder frei.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:29 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