Autor |
Beitrag |
Master_of_Magic
      
Beiträge: 56
Win 98, Win XP
D6 Pers, D2005 Arch
|
Verfasst: Mo 17.04.06 15:31
Ich bin gerade dabei mir eine kleine Datenbankanwendung zu basteln ('Datenbank' ist etwas übertrieben  ). 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:
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 
      
Beiträge: 56
Win 98, Win XP
D6 Pers, D2005 Arch
|
Verfasst: 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 ... 
|
|
alias5000
      
Beiträge: 2145
WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
|
Verfasst: 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?
_________________ Programmers never die, they just GOSUB without RETURN
|
|
Master_of_Magic 
      
Beiträge: 56
Win 98, Win XP
D6 Pers, D2005 Arch
|
Verfasst: 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
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: 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 
      
Beiträge: 56
Win 98, Win XP
D6 Pers, D2005 Arch
|
Verfasst: 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:
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 ...
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
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: 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 
      
Beiträge: 56
Win 98, Win XP
D6 Pers, D2005 Arch
|
Verfasst: 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 '...)
|
|
|