Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Daten ändern sich "von alleine" (https://www.delphipraxis.net/142778-daten-aendern-sich-von-alleine.html)

dominikkv 3. Nov 2009 16:53


Daten ändern sich "von alleine"
 
Hi,

ich hab irgendwie nen Geist in meinem Programm, der mich ein bisschen ärgert :twisted:
Und zwar verändert der ab und zu Daten in einem Record.

Zuerst der Aufbau:
Delphi-Quellcode:
type
  PCategory = ^TCategory;
  PCategories = array of PCategory;

  TArticle = record
    Link, Name: string;
    Parents: PCategories; // In welchen Kategorien ist der Artikel?
    Preis: Currency;
  end;
  TArticles = array of TArticle;
  PArticle = ^TArticle;
  PArticles = array of PArticle;

  TCategory = record
    Name, Link: string;
    Children: PCategories; // Falls die Kategorie Unterkategorien hat
    Parent: PCategory;    // Falls die Kategorie eine Unterkategorie ist
    Articles: PArticles;  // welche Artikel sind in der Kategorie?
  end;
  TCategories = array of TCategory;

var // global
  _Categories: TCategories;
  _Articles: TArticles;
Mein Programm füllt nun diese Arrays. Während des füllens passiert etwas komisches:
Die ersten paar Datensätze werden korrekt in das Array eingetragen, dann, ohne dass ich auf die Arrays zugreifen würde, ändern sich die Daten im Array, und zwar wird zuerst _Categories[3].Articles[0] verändert, dann so nach und nach die anderen Artikel von _Categories[3]. Und zwar sieht das immer so aus, als ob der Record noch nicht initialisiert wäre, zB in .Name stehen irgendwelche Zeichen, der .Preis ist irgend eine exorbitantische Zahl und der Artikel hat plötzlich 763753 Parents, die alle auf nil stehen.

Das lustige ist, das passiert zB bei dieser Zeile, aber auch nur beim 3ten Aufruf:
Delphi-Quellcode:
_Temp := StringReplace(_Temp, '/nocache', '', []); // _Temp ist eine lokale Variable
Wenn ich das so umschreibe...
Delphi-Quellcode:
Delete(_Temp, Pos('/nocache', _Temp), 8);
...tritt dieser Fehler nicht auf, dafür dann an einer anderen Stelle.

Kann mir das einer erklären?
Das einzige, was ich mir vorstellen kann, ist dass Delphi die Daten des Artikels im Speicher verschiebt, ich aber über meinen Zeiger auf den alten Speicherplatz zugreifen will. Ich rufe bei jedem neuen Artikel SetLength(_Articles, Length(_Articles) + 1); auf. Aber warum ändern sich die Daten dann erst viel später, und nicht direkt bei SetLength()?
Ich habe auch schon gehört, dass bei nicht richtig synchronisierten Threads komische Fehler auftreten können, deshalb habe ich alle Threads, die ich erstellt habe, erstmal wieder rückgängig gemacht, an denen kanns also nicht liegen.

Ich habe schon alles mögliche versucht, mit und ohne Debugger, mit und ohne automatischer Code-Optimierung usw, ich bin mit meinem Latein (oder doch eher Delphi? :cyclops: ) am Ende :roll:


Vorschläge sind herzlich willkommen :lol:

mfg.Dominik

DeddyH 3. Nov 2009 17:03

Re: Daten ändern sich "von alleine"
 
IIRC wird per SetLength() das Array ggf. in einen anderen Speicherbereich kopiert, der ausreichend zusammenhängenden Speicher bietet. Dadurch greifen dann Deine gemerkten Pointer ins Leere. Alternativen wären neben einer Datenbank verkettete Listen. Letztere müssen nicht "am Stück" im Speicher liegen.

p80286 3. Nov 2009 17:05

Re: Daten ändern sich "von alleine"
 
Hallo Dominik

Wenn ich da nichts übersehen habe, dann fehlt schlicht und ergreifend das SetLength. Wenn Du keinen Speicherbereich für deine Variablen reservierst/anlegst, dann schreibst Du wild in den Speicher. Warum gibt's da eigentlich keine Fehlermeldung??

dominikkv 3. Nov 2009 17:35

Re: Daten ändern sich "von alleine"
 
Zitat:

Zitat von DeddyH
IIRC wird per SetLength() das Array ggf. in einen anderen Speicherbereich kopiert, der ausreichend zusammenhängenden Speicher bietet. Dadurch greifen dann Deine gemerkten Pointer ins Leere. Alternativen wären neben einer Datenbank verkettete Listen. Letztere müssen nicht "am Stück" im Speicher liegen.

Ok, hast recht. Nachdem ich nun gleich von Anfang an das Array auf 100000 Elemente gesetzt habe ist der Fehler weg. :wall:

Zitat:

Zitat von p80286
Wenn ich da nichts übersehen habe, dann fehlt schlicht und ergreifend das SetLength. Wenn Du keinen Speicherbereich für deine Variablen reservierst/anlegst, dann schreibst Du wild in den Speicher. Warum gibt's da eigentlich keine Fehlermeldung??

Zitat:

Zitat von dominikkv
Ich rufe bei jedem neuen Artikel SetLength(_Articles, Length(_Articles) + 1); auf.

Aber trotzdem Danke für deine Hilfe :cheers:

himitsu 3. Nov 2009 17:43

Re: Daten ändern sich "von alleine"
 
Man könnte natürlich auch einfach alle Pointer, welche auf dieses Elemente dieses Arrays zeigen, anpassen\umrechnen, so daß sie dann wieder stimmen.

Liegen denn alle TArticles und TCategory nur in diesen beiden Arrays?

[add]
Delphi-Quellcode:
Procedure CategoriesSetLength(Var Categories: TCategories; i: Integer);
  Var i, i2: Integer;

  Begin
    i2 := Integer(Categories);
    SetLength(Categories, i2);
    Dec(i2, Integer(Categories));
    If i2 = 0 Then Exit;
    For i := High(Categories) downto 0 do Begin
      If Assigned(Categories[i].Children) Then
        Dec(Integer(Categories[i].Children), i2);
      If Assigned(Categories[i].Parent) Then
        Dec(Integer(Categories[i].Parent), i2);
    End;
  End;
Wobei ich einfach statt des Pointers den Index im Array speichern würde, da braucht man nichts umrechnen, welbst wenn sich das Array mal verschiebt.

dominikkv 3. Nov 2009 18:12

Re: Daten ändern sich "von alleine"
 
Zitat:

Zitat von himitsu
Liegen denn alle TArticles und TCategory nur in diesen beiden Arrays?

Ja.
Zitat:

Zitat von himitsu
Man könnte natürlich auch einfach alle Pointer, welche auf dieses Elemente dieses Arrays zeigen, anpassen\umrechnen, so daß sie dann wieder stimmen.

Das wäre eine Idee. Nur wie kann ich die umrechnen?
Ich könnte zB die alte Speicheradresse von _Articles[0] mit deren neuen vergleichen und den Unterschied auf alle Pointer dazuaddieren/abziehen.
Delphi-Quellcode:
var
  Unterschied: Integer; // richtiger Typ?
  I, J, K: Integer;
begin
  Unterschied := Addr(_Articles[0]) - _Articles[0].Parents[0]^.Articles[0];

  for I := 0 to Length(_Categories) - 1 do
    begin
      for J := 0 to Length(_Categories[I].Articles) do
        _Categories[I].Articles[J] := _Categories[I].Articles[J] + Unterschied;
      for J := 0 to Length(_Categories[I].Children) do
        for K := 0 to Length(_Categories[I].Children[J]^.Articles) do
          _Categories[I].Children[J]^.Articles[K] := _Categories[I].Children[J]^.Articles[K] + Unterschied;
    end;
end;
Das will aber nicht so recht...[DCC Fehler] E2015 Operator ist auf diesen Operandentyp nicht anwendbar

guidok 4. Nov 2009 06:43

Re: Daten ändern sich "von alleine"
 
Wäre es nicht besser, sich einfach von den Records zu verabschieden und die Daten in Objekten zu speichern?

Da gibt es dann einige einfache Möglichkeiten: TCollection, TObjectList...


Hier ist ein Beispiel, wie eine TCollection angewendet wird (natürlich in einem ganz anderen Zusammenhang).


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