Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Pointer wirrwarr. Bitte um hilfe (https://www.delphipraxis.net/188162-pointer-wirrwarr-bitte-um-hilfe.html)

hedie 4. Feb 2016 21:32

Pointer wirrwarr. Bitte um hilfe
 
Hallo zusammen

Dieser Code war meine Grundlage:
Delphi-Quellcode:
type
  TTreeData = record
    FCaption: string;
    FColumn1: string;
  end;
  PTreeData = ^TTreeData;
...
procedure TForm1.Button2Click(Sender: TObject);
var
  Node : PVirtualNode;
  Data:PTreeData;
begin

  //Data ist nur ein Pointer auf eine Datenstruktur von TTreeData;
  vst.BeginUpdate;

  //Zuerst holen wir uns den Node
  Node := VST.AddChild(nil);

  //VST kennt bereits die grösse der Struktur und hat hier genau soviel Speicher bereit gestellt
  //Wir übergeben Data nun die Adresse des Speichers von VST.
  Data := vst.GetNodeData(node);

  //Nun können wir direkt in den Node Speicher hinein schreiben.
  Data^.FCaption := 'Test';
  Data^.FColumn1 := 'Column';

  vst.EndUpdate;

end;
Wie man erkennen kann, handelt es sich um VirtualTreeView.


Ich habe nun versucht anstelle des Records ein dynamisches array bestehend aus strings zu benutzen.
Dazu habe ich folgendes versucht:


Delphi-Quellcode:
type
  TsqlData = array of string;
  PsqlData = ^TsqlData;

...


function TeVCLqueryTable.Query(Query: string):integer;
var
  row,col:integer;
  node:PVirtualNode;
  sqlData:PsqlData;
begin
  FMySQL.Query(Query);

  //SQLColCount ist 11
  for col := 0 to FMySQL.SQLColCount - 1 do begin
    FVST.Header.Columns.Add;
  end;

  FVST.BeginUpdate;
 
  SetLength(sqlData^,FMySQL.SQLColCount); //SQLColCount ist 11
  FVST.NodeDataSize := sizeof(sqlData);

  node := FVST.AddChild(nil);
  sqlData := FVST.GetNodeData(node);

  sqlData^[0] := 'Test'; //<-- Hier kommt eine exception

  Result := FMySQL.SQLRowCount;

  FVST.EndUpdate;
end;


Ich wäre froh, wenn mir hier jemand weiterhelfen könnte.

Es geht um das Problem mit den Pointern.
Irgendwas mache ich falsch ^^

Danke

EmWieMichael 5. Feb 2016 07:05

AW: Pointer wirrwarr. Bitte um hilfe
 
Deine Pointer zeigen ins Nirwana. Sieh Dir mal 'New' und 'Dispose' an...

Gruß Michael

Lemmy 5. Feb 2016 07:20

AW: Pointer wirrwarr. Bitte um hilfe
 
Zitat:

Zitat von hedie (Beitrag 1329459)
Ich habe nun versucht anstelle des Records ein dynamisches array bestehend aus strings zu benutzen.
Dazu habe ich folgendes versucht:
.....
Es geht um das Problem mit den Pointern.
Irgendwas mache ich falsch ^^

ich habe zwar schon lange nicht mehr mit dynamischen Arrays gearbeitet, aber wenn ich das noch richtig im Kopf habe, sollte man da über SetLength und co. doch entsprechenden Speicher reservieren? Sprich nach deinem GetNodeData() solltest Du schauen wie groß das Array ist und dann über SetLength ggf. weitere ELemente dazu fügen.

Neutral General 5. Feb 2016 07:42

AW: Pointer wirrwarr. Bitte um hilfe
 
Zitat:

Zitat von Lemmy (Beitrag 1329479)
ich habe zwar schon lange nicht mehr mit dynamischen Arrays gearbeitet, aber wenn ich das noch richtig im Kopf habe, sollte man da über SetLength und co. doch entsprechenden Speicher reservieren? Sprich nach deinem GetNodeData() solltest Du schauen wie groß das Array ist und dann über SetLength ggf. weitere ELemente dazu fügen.

Er hat ein Pointer auf ein dynamisches Array, deswegen muss er wie EmWieMichael gesagt hat mit New das Array erzeugen und danach erst mit SetLength die größe des Arrays setzen.
(Später dann wie gesagt mit Dispose die Arrays frei geben!)

Uwe Raabe 5. Feb 2016 10:58

AW: Pointer wirrwarr. Bitte um hilfe
 
Oder man macht es wie im oberen Beispiel mit den Strings und packt einen Record um das Array. Dann muss man aber auch im OnFreeNode das Array wieder auf nil setzen.

Delphi-Quellcode:
type
  TsqlData = record
    Data: array of string;
  end;
  PsqlData = ^TsqlData;

procedure ...GetNodeDataSize(Sender: TBaseVirtualTree;
  var NodeDataSize: Integer);
begin
  { Alle Nodes haben dieselbe DataSize! Aber nicht alle Nodes müssen zwingend dieselbe Array-Länge haben. }
  NodeDataSize := SizeOf(TsqlData);
end;

procedure ...FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  sqlData:PsqlData;
begin
  sqlData := Sender.GetNodeData(node);
  sqlData.Data := nil;
end;

function Query(Query: string):integer;
var
  row,col:integer;
  node:PVirtualNode;
  sqlData:PsqlData;
begin
  FMySQL.Query(Query);

  //SQLColCount ist 11
  for col := 0 to FMySQL.SQLColCount - 1 do begin
    FVST.Header.Columns.Add;
  end;

  FVST.BeginUpdate;
  try
    node := FVST.AddChild(nil);
    sqlData := FVST.GetNodeData(node);
    SetLength(sqlData.Data,FMySQL.SQLColCount); //SQLColCount ist 11
    sqlData[0] := 'Test';
  finally
    FVST.EndUpdate;
  end;

  Result := FMySQL.SQLRowCount;
end;

Lemmy 5. Feb 2016 11:19

AW: Pointer wirrwarr. Bitte um hilfe
 
Zitat:

Zitat von Neutral General (Beitrag 1329481)
Er hat ein Pointer auf ein dynamisches Array....

hmm... Ich gebe ja gerne zu, dass ich mit Pointern schon immer so meine Probleme habe. Aber was gibt denn .GetNodeData bitte schön zurück, wenn nicht einen pointer auf einen Speicherbereich in das das array gehört? Den Bereich definiere ich mit NodeDataSize und der VST kümmert sich drum, dass dort ein Pointer mit der Größe angelegt wird. Wie ich den interpretiere ist dann meine Sache - auch wenn ich innerhalb dieses Pointers auf weitere Speicherbereiche zugreife die ich dann zu verwalten habe....

Das hier funktioniert bei mir problemlos:

Delphi-Quellcode:

procedure TForm1.FormCreate(Sender: TObject);
begin
  FVST.NodeDataSize := sizeof(PsqlData);
end;

procedure TForm1.Button1Click(Sender: TObject);
var sqlData:PsqlData;
   node:PVirtualNode;
begin
  node := FVST.AddChild(nil);
  sqlData := FVST.GetNodeData(node);
  SetLength(sqlData^, 2);
  sqlData^[0]:='Hallo';
  sqlData^[1]:='Welt';
end;

procedure TForm1.FVSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var sqlData:PsqlData;
idx: Integer;
begin
  sqlData := FVST.GetNodeData(Node);
  CellText := '';
  if Assigned(sqlData) then
  begin
    for idx := 0 to length(sqlData^) - 1 do
    begin
      CellText := CellText + sqlData^[idx];
    end;
  end;

end;
Es fehlt noch die Freigabe der dynamischen Arrays bei beenden.
Ich wüsste auch nicht wo genau jetzt der Unterschied zwischen einem dynamischen Array und dem Record von Uwes Beispielcode sein soll. Es sind am Ende Variablen. Ich wäre echt dankbar, wenn mir jemand das erklären kann...

Uwe Raabe 5. Feb 2016 12:39

AW: Pointer wirrwarr. Bitte um hilfe
 
Zitat:

Zitat von Lemmy (Beitrag 1329507)
Ich wüsste auch nicht wo genau jetzt der Unterschied zwischen einem dynamischen Array und dem Record von Uwes Beispielcode sein soll. Es sind am Ende Variablen. Ich wäre echt dankbar, wenn mir jemand das erklären kann...

Der Unterschied ist rein semantisch. Die Speicherstruktur und der erzeugte Code sind wohl so gut wie identisch. Der Record-Ansatz erfordert halt keine Pointer-Dereferenzierung und ist später leichter zu erweitern, aber das muss hier ja nicht unbedingt ein Kriterium sein.

hedie 5. Feb 2016 17:07

AW: Pointer wirrwarr. Bitte um hilfe
 
Vielen Dank für eure Hilfe.
Dies habe ich nun verstanden und es hat auch geklappt!

Nu habe ich gleich noch eine andere Frage zum selben Thema.

Ich habe bei mir in der hauptunit ein ObjektA erstellt, welches ich im private bereich deklariert habe.
Dieses erstelle ich beim öffnen der Anwendung.

Während der Laufzeit, möchte ich mit diesem ObjektA arbeiten.
Um mit diesem ObjektA arbeiten zu können, habe ich mir eine zweite Klasse geschrieben, welche die entsprechenden "bearbeitungs methoden" beinhaltet. Damit ich mit dieser Klasse arbeiten kann, muss ich davon ja auch ein ObjektB erstellen. Soweit so gut. Klappt auch.

Nun möchte ich bei einem Button click, das ObjektB, welches mir Hilft ObjektA zu bearbeiten, erstellen -> verwenden -> und wieder freigeben.

Hier gibts das Problem. Da ich bisher nicht ans freigeben gedacht habe, hab ich das erst jetzt bemerkt.

Ich übergebe ObjektB folgendes beim Create:

Delphi-Quellcode:
FVST:TVirtualStringTree;
FMySQL:TmySQLe;

constructor TeVCLqueryTable.Create(const VST: TVirtualStringTree; const MySQL:TmySQLe);
begin
  FVST := VST;
  FMySQL := MySQL;
...
Beim ObjectB.Free bekomme ich eine Exception.
Ich vermute mal, dass es dabei auch die übergebenen Objekte VST und MySQL freigegeben hat.
Dann wäre mir klar, dass es nicht mehr funktioniert!

Eigentlich möchte ich nur einen Pointer auf das ObjektA bzw. VST und MySQL damit ich mit diesen bereits existierenden Objekten innerhalb meines neuen Objektes arbeiten kann.

Nach dem Freigeben von ObjektB sollen die Objekte VST und MySQL weiterleben.


Könnte mir hier jemand weiterhelfen?

Vielen Dank :)

hoika 5. Feb 2016 17:10

AW: Pointer wirrwarr. Bitte um hilfe
 
Hallo,
wie sieht denn der Destructor der Klasse TeVCLqueryTable (also von ObjectB) aus, den Constructor sehe ich ja.


Heiko

hedie 5. Feb 2016 17:12

AW: Pointer wirrwarr. Bitte um hilfe
 
Bisher sieht der so aus:

Delphi-Quellcode:
destructor TeVCLqueryTable.Destroy;
begin

  //FVST := nil;
  //FMySQL := nil;

  inherited;
end;
Wie du an den kommentaren siehst, war ich mir nicht ganz sicher... ^^


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:53 Uhr.
Seite 1 von 2  1 2      

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