![]() |
Problem mit einer Stringlist und Pointern
Hallo DPler!
Ich habe in meinem Programm folgendes vor: Ich will einen Stromkreis darstellen, der auch ineinander verschachtelte Parallel und Reihenschaltungen beimhalten kann, dazu habe ich mir folgendes überlegt:
Delphi-Quellcode:
Jetzt habe ich ein Prozedur zum einfügen neuer Bauteile
// Ich habe zunächst meinen Typ TBauteil
type TBauteil = Record ID,Parent: string; // Jedes Bauteil hat eine eindeutige ID Typ: TBauteilTyp; Next: Array of PBauteil end; // und einen Pointertyp für TBauteil PBauteil = ^TBauteil; // Und zu guter Letzt noch meine Klasse für das verketten von Bauteilen TBauteilListe=class(Tobject) private FRoot: PBauteil; function GetBauteil(ID: string): PBauteil; function GetLines: TStringlist; procedure NilBauteile; public constructor Create; destructor Destroy; override; function AddBauteil(ID: string; Typ: TBauteilTyp; Parent: string): boolean; property Items[ID: string]: PBauteil read GetBAuteil; property Lines: TStringlist read GetLines; end;
Delphi-Quellcode:
Bis dahin klappts auch, aber bei dieser Methode knallts, weil die Stringlist leer ist, obwohl ich per Breakpoint gesehen habe, dass die Inhalte ewrkannt werden
function TBauteilListe.AddBauteil(ID: string; Typ: TBauteilTyp;
Parent: string): boolean; var p: PBauteil; begin p := GetBauteil(Parent); if p <> nil then begin setlength(p^.Next,length(p^.Next)+1); new(p^.Next[high(p^.next)]); p^.Next[high(p^.next)]^.ID := ID; p^.Next[high(p^.next)]^.Typ := Typ; result := true; end else result := false; end; // wobei GetBauteil so aussieht function TBauteilListe.GetBauteil(ID: string): PBauteil; procedure Rekursiv(p: PBauteil; Search: string; var result: PBauteil); var i: integer; begin if p <> nil then if p^.ID = Search then result := p else if p^.Next <> nil then for i := low(p^.next) to high(p^.next) do Rekursiv(p^.next[i],Search,p); end; begin Result := nil; Rekursiv(FRoot,ID,Result); end;// Man Gibt also bei den Parent (also Vorgänger) des Einzufügenden Bauteils an, dann wird das Dynamische Array of Pointer um eins erweitert und ein Neues Bauteil eingefügt
Delphi-Quellcode:
Was mache ich bei der benutzung der Stringlist falsch? Daran wirds wohl liegen, denn der Fehler tritt genau dann auf, wenn er die Listbox1.Items setzt, und zwar auf das Result, das trotzdem nur den wert
function TBauteilListe.GetLines: TStringlist;
procedure Rekursiv(p: PBauteil; var Lst: TStringlist); var i: integer; begin if p <> nil then begin if p^.Next <> nil then for i := low(p^.next) to high(p^.next) do begin Rekursiv(p^.next[i],Lst); end; Lst.Add(p^.ID) // #1 Hier wird die ID hinzugefügt, was ich mit Breakpoint herausfand end; end; var Lst: TStringlist; begin Lst := TStringList.Create; Lst.Clear; Rekursiv(FRoot,Lst); Result := Lst; // Das Result ist leer, und list ist auch leer, obwohl an #1 mein Hinzugefügter EIntrag zu sehen ist Lst.Free; end;
Delphi-Quellcode:
Danke schonmal für die Hilfe!
Result = ()
Richard Edit: Ich habe mal den Titel geändert, das Problem bezieht sich ja gar nicht auf die Pointer Edit: Titel nochmals geändert, jetzt sinds doch Pointer :spin2: |
Re: Problem mit einer Stringlist
1. Gib mal den Pointer der Tstringlist mit const (statt var) über. Ich bin mir zwar nicht sicher, ob das wirklich einen Unterschied macht. Ich finds besser.
2. Stell dir vor du erstellst die Liste an Adresse A. Dann übergibst du diese Adresse an Result (also steht in Result A drinn). Soweit ist alles klar. Jetzt löschst du die liste mit lst.free. Result zeigt immer noch auf A, aber dort steht nix mehr drinn. --> Lass mal das Löschen(freigeben) weg. Das machst du besser nachdem du das Result in der aufrufenden Funktion verarbeitet hast. Besser ist noch du benutzt von anfang an Result:
Delphi-Quellcode:
function TBauteilListe.GetLines: TStringlist;
... begin Result := TStringList.Create; Result.Clear; //ist denk ich nicht zwingend notwendig Rekursiv(FRoot,Result); //free übernimmt die aufrufende Funktion end; ... //Aufrufende Funktion: var ergebnis:TStringlist; begin ergebnis:=getlines; // mit ergebnis arbeiten ergebnis.free; end; |
Re: Problem mit einer Stringlist
var Lst: TStringlist;
begin Lst := TStringList.Create; Lst.Clear; Rekursiv(FRoot,Lst); Result := Lst; // Das Result ist leer, und list ist auch leer, obwohl an #1 mein Hinzugefügter EIntrag zu sehen ist Lst.Free; // meines Erachtes löscht Du hiermit auch die Referenz auf die Result zeigt. end;
Delphi-Quellcode:
Grüße
var Lst: TStringlist;
begin result:=TStringList.create; Lst := TStringList.Create; Lst.Clear; Rekursiv(FRoot,Lst); Result.Text := Lst.Text; Lst.Free; end; Klaus |
Re: Problem mit einer Stringlist
Hallo Richard,
den gröbsten Schnitzer hat dir sirius bereits mitgeteilt. Lines ist bei dir als read-only property vereinbart, aber es ist von seiner Bedeutung her gar keine property. Du erzeugst bei jedem Aufruf eine neue StringList - denkst du daran sie auch wieder zu zerstören? Wenn du alle Bauteile einer Baugruppe (bill-of-material) rekursiv ermitteln und als StringList zurückgeben möchtest, dann hast du zwei bessere Möglichkeiten: Du stellst eine public function CreateList: TStringList zur Verfügung und achtest darauf, dass du diese List zu gegebener Zeit auch wieder freigibts, oder du verwaltest die Liste außerhalb der Methode und übergibst die Liste beim Aufruf. Die Methode kann dann eine public procedure MakeList(s: TStrings) sein. Grüße vom marabu |
Re: Problem mit einer Stringlist
Zitat:
Wie du an meinem Post siehst, dein Gedanke ist meinem gleich. Aber deine Lösung funktioniert so nicht, da du von Result auch mal mit den Constructer aufrufen solltest. :zwinker: |
Re: Problem mit einer Stringlist
Delphi-Quellcode:
So scheint das zu Funkrionieren aber:
function TBauteilListe.GetLines: TStringlist;
procedure Rekursiv(p: PBauteil; var Lst: TStringlist); var i: integer; begin if p <> nil then begin if p^.Next <> nil then for i := low(p^.next) to high(p^.next) do begin Rekursiv(p^.next[i],Lst); end; Lst.Add(p^.ID) end; end; var Lst: TStringlist; begin Result := TStringList.Create; Lst := TStringlist.Create; Result.Clear; Lst.Clear; Rekursiv(FRoot,Lst); Result := lst; end;
Delphi-Quellcode:
Was ist mit dem Speicher, auf den der Pointer vorher gezeigt hat?
Result := Lst;
Und wenn ich Result oder Lst freigebe, dann dann ist das Result ja wieder nil, folglicherweise müsste es dann doch wider krachen oder? Wo kann ich die Listen wieder freigeben? Das habe ich noch nicht ganz verstanden |
Re: Problem mit einer Stringlist
Schmeiss das Lst ganz raus und benutze nur Result (ist ne ganz normale Variable, die nicht definiert werden muss), oder wozu brauchst du zwei Listen?
und mach mal daraus procedure Rekursiv(p: PBauteil; var Lst: TStringlist); dass hier procedure Rekursiv(p: PBauteil; const Lst: TStringlist); |
Re: Problem mit einer Stringlist
... wenn er deinem Rat folgt, hat er kein Result mehr in der Methode. :gruebel:
|
Re: Problem mit einer Stringlist
Zur Verdeutlichung meines Hinweises aus Beitrag #4:
Delphi-Quellcode:
Freundliche Grüße
procedure TBauteilListe.MakeList(const s: TStrings);
procedure FetchItem(p: PBauteil); var i: integer; begin if Assigned(p.Next) then for i := Low(p.Next) to High(p.Next) do if Assigned(p.Next[i]) then FetchItem(p.Next[i]) else s.Add(p.ID) end; begin s.Clear; FetchItem(FRoot); end; |
Re: Problem mit einer Stringlist
Ich habe aus den Funktionen Prozedure gemacht, wie es scheint ist rekursion bei Funktionen nicht immer optimal...
Jedenfalls funktionierts jetzt Danke für eure Hilfe! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:52 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz