Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Records in dyn. Array einfügen und löschen
Master_of_Magic - Mo 17.04.06 15:31
Titel: Records in dyn. Array einfügen und löschen
Ich bin gerade dabei mir eine kleine Datenbankanwendung zu basteln ('Datenbank' ist etwas übertrieben :wink: ). Die Datensätze bestehen dabei aus dem Record:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| type TUser = record id:word; name:string; gala:byte; mail:string; pdate:word; paccount:byte; pamount:word; state:byte; hddsn:cardinal; winsn:cardinal; lansn:cardinal; cpusn:cardinal; comment:string; end;
var user: array of TUser; |
Die Daten werden in den Stringgrid
db dargestellt. Um einen Datensatz zu löschen hab ich mir folgende Prozedur gebastelt (Teile im Forum gefunden):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TForm1.deleteClick(Sender: TObject); var index,i:integer; begin index:=db.Selection.Top-1;
Finalize(user[index]); Move(user[index + 1], user[index], SizeOf(TUser) * (High(user) - index)); FillChar(user[High(user)], SizeOf(TUser), 0); SetLength(user, High(user));
db.Row := index+1; if (db.Row = db.RowCount -1) then db.RowCount := db.RowCount - 1 else begin for i := index+1 to db.RowCount-1 do db.Rows[i] := db.Rows[i+1]; db.RowCount := db.RowCount - 1; end;
displayrecord(index); end; |
Das funktioniert soweit - trotzdem bleiben stellen sich mir 3 Fragen:
1. Welche Bedeutung hat
Finalize in diesem Zusammenhang?
2. Warum kann ich die Daten einfach mit
move verschieben, obwohl der Record dynamische(!) Strings enthält?
3. Weshalb liefert
SizeOf(TUser) immer den Wert 44 und wie setzt sich dieser zusammen?
Nun zu meinem eigentlichen Problem.
Zum Einfügen eines neuen Datensatzes verwende ich folgende Prozedur:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| procedure TForm1.insertClick(Sender: TObject); var index,i:integer; begin index:=db.Selection.Top-1;
SetLength(user, Length(user)+1); Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index));
with user[index] do begin if index=0 then id:=1 else id:=user[index-1].id; name:=''; gala:=0; mail:=''; pdate:=38353; pamount:=0; paccount:=0; state:=5; hddsn:=0; winsn:=0; lansn:=0; cpusn:=0; comment:=''; end;
displaydbentry(index+1,index); displayrecord(index);
db.RowCount:=db.RowCount+1; for i := db.RowCount-2 downto index+1 do db.Rows[i+1] := db.Rows[i]; end; |
Da scheint jetzt irgendein Fehler (ich tipp im
move-Teil) zu sein, da nachfolgende Datensätze (bzw. deren Strings) zerhackstückt werden. Außerdem erhalte ich beim Speichern des user-Arrays eine Zugriffsverletzung ...
Weiß einer, woran das liegt?
Master_of_Magic - Sa 22.04.06 15:57
hmm, da anscheinend niemand eine Antwort auf meine Frage(n) weiß, will ich sie mal umformulieren:
Kann mir einer sagen, wie ich Record-Elemente in ein (dyn.) Array einfügen bzw. zwei Records vertauschen kann?
Der obige Code ist nur mein bisheriges Ergebnis - der muss also nicht beibehalten werden ... :wink:
alias5000 - Sa 22.04.06 16:14
Vertauschen (allgemein formuliert):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| Procedure Exchange(index1, index2: integer); var Rec: TMyRecord; begin Rec := RecArray[index1]; RecArray[index1] := RecArray[index2]; RecArray[index2] := Rec; end; |
Hilft das weiter?
Master_of_Magic - So 23.04.06 14:52
Ok, auf das Vertauschen hätt ich auch selber kommen können - ist ja quasi BubbleSort ...
Aber kann ich einfach so zwei Datensätze vertauschen? Weil die haben ja durch den String eine verschiedene Größe, oder?
Horst_H - So 23.04.06 15:14
Hallo,
der String ist ja ein Zeiger auf eine String-Struktur, deshalb klappt es.
Die Strings selber stehen also nicht im record sondern woanders.
Diese werden also nie verschoben, wenn Du dein array user vergroesserst oder verkleinerst.
Beim nach oben schieben muesste:
Move(Von,Nach,Anzahl)
Delphi-Quelltext
1:
| Move(user[index + 1], user[index], SizeOf(TUser) * (High(user) - index)); |
wohl
Delphi-Quelltext
1:
| Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index)); |
sein.
Aber bei Dir haette trotzdem kein Muell auftreten duerfen, sondern der letzt Datensatz waer doppelt vorhanden und der an der Position Index einfach ueberschrieben.
Gruss Horst
Master_of_Magic - Mo 24.04.06 18:34
@Horst_H
Das heißt also, ich kann meine Records beliebig verschieben und vertauschen, da die Daten selbst nicht verändert werden, oder? Das macht die Sach einfacher ... *freu*
Deine Code-Schnipsel blick ich nicht ganz: was meinst du mit 'nach oben schieben'? Meine zwei Code-Teile oben sind nur zum löschen und einfügen eines Records:
Beim Löschen werden die user[index+1] nach user[index] verschoben und beim einfügen andersrum - von daher stimmt das doch.
Was mein Problem angeht: Ich habe herausgefunden, dass das Array passt, jedoch nur die Anzeige Müll liefert. Liegt von an den letzten Zeilen der Procedure, die falsch herum waren. Meine Procedure sieht nun so aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| procedure TForm1.insertClick(Sender: TObject); var index,i:integer; begin index:=db.Selection.Top-1;
SetLength(user, Length(user)+1);
Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index));
with user[index] do begin if index=0 then id:=1 else id:=user[index-1].id; name:='Name'; gala:=0; mail:='Mail'; pdate:=38353; pamount:=0; paccount:=0; state:=5; hddsn:=0; winsn:=0; lansn:=0; cpusn:=0; comment:=''; end;
db.RowCount:=db.RowCount+1; for i := db.RowCount-2 downto index+1 do db.Rows[i+1] := db.Rows[i];
displaydbentry(index+1,index); displayrecord(index);
end; |
Nun passt die Anzeige und das Einfügen klappt auch - meistens. Manchmal (v.a. beim Beenden) erhalte ich jedoch eine 'Invalid Pointer Operation', eine 'AccessViolation' oder in seltenen Fällen sogar eine Zugriffsverletzung auf die Kernel.dll ... :shock:
Verwende ich jedoch eine For Schleife (die die im Code oben auskommentiert ist) klappt alles wunderbar ohne Fehler.
Im Prinzip ist mein Problem damit gelöst, jedoch wurde ich doch gerne die Ursache der
move-Fehler wissen ... kann mir da einer helfen?
Horst_H - Mo 24.04.06 19:29
Hallo,
Du bewegst ein record zu wenig (auch beim Loeschen) also,
Delphi-Quelltext
1:
| Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index +1)); |
denn 1..10 nach 2..11 verschieben sind 10 Elemente aber 10-1=9.
Deshalb hat deine Variable Comment (=string= Zeiger auf eine Delphi-StringStruktur) eine Zuordnung in die unendlichen Weiten des Hauptspeichers(, in die noch nie ein Bit vorgedrungen ist, oder total verbotene Bereiche access violation).
Dies kann also zu Mist fuehren.
Gruss Horst
Master_of_Magic - Di 25.04.06 18:58
Nein, das hast du was vergessen:
Bevor ich move anwende, wird ja das Array bereits um 1 vergrößert (beim
Einfügen)! High(user) liefert also bereits 11 zurück (um bei deinem Beispiel zu bleiben). Somit passt das wieder (11-1=10 Elemente zu verschieben).
Dein Quellcode liefert daher eine Zugriffsverletzung (bzw. eine 'Debugger Fault Notification '...)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!