Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Element aus Dynamischem Array entfernen?
Delete - Sa 10.07.04 12:17
Titel: Element aus Dynamischem Array entfernen?
Hallo,
Ich bin dabei ein kleines Verwaltungsprogramm zu schreiben. Um einträge zu löschen, müsste ich wissen, wie ich aus einem dynamischen Array ein Element "heraustrenne". Praktisch so, dass die übrigen Elemente eins aufrutschen.
Delphi-Quelltext
1: 2:
| var Liste: array of TDatenRec; SetLength(Liste, 20); |
Nun soll z.B. das 10. Element enternt werden und die Liste soll danach noch 19 Elemente haben.
Dankeim Voraus!
Moderiert von
Peter Lustig: Topic aus VCL (Visual Component Library) verschoben am Sa 10.07.2004 um 12:20
Schattengeist - Sa 10.07.04 12:20
'per Hand'
Alle hochrücken, dann die Liste kürzen.
Hmmm. Wir verwenden für sowas StingListen/ObjektListen. Da ist sowas alles schon drin. Man muß nur das alles als Objekte vorliegen haben.
Muetze1 - Sa 10.07.04 12:39
Moin!
Wieso Objekte? Nimm TList und dann kannste das gleiche auch mit deinen Records machen...
MfG
Muetze1
bms - Sa 10.07.04 12:56
Titel: Re: Element aus Dynamischem Array entfernen?
| Elite* hat folgendes geschrieben: |
Um einträge zu löschen, müsste ich wissen, wie ich aus einem dynamischen Array ein Element "heraustrenne". Praktisch so, dass die übrigen Elemente eins aufrutschen.
Delphi-Quelltext 1: 2:
| var Liste: array of TDatenRec; SetLength(Liste, 20); |
Nun soll z.B. das 10. Element enternt werden und die Liste soll danach noch 19 Elemente haben. |
Wie gesagt per Hand. Allerdings kannst du das ein wenig anders angehen. Du löscht den Wert nicht, sondern gibst ihm eine Löschmarke. In deinem Programm achtest du dann, daß du nur Werte verwendest die keine Löschmarke haben. Zur gegebner Zeit kann der User dann die Datenbank komprimieren. Hier wird dann nicht gezipt, sondern der Array wird von gelöschten Werten befreit. Anders machen es übrigens auch die Datenbanken nicht. Sie belassen die gelöschten Werte und löschen die erst wenn die Datenbank komprimiert wird.
Schattengeist - Sa 10.07.04 13:02
Da es sich nur um Speichertabellen handelt, finde ich, das Löschmarken etwas zu aufwendig sind.
Mal eben kurz das zu eleminieren sollte nicht soooo zeitfressend sein.
Gausi - Sa 10.07.04 13:45
naja...für solche Operationen würde ich trotzdem dringendst ein Listenstruktur empfehlen. Besonders dann, wenn solche Lösch- (und Einfüge-) operationen öfter auftreten, und die Anzahl der Objekte groß ist.
Delete - Sa 10.07.04 17:39
Wenn ich jetzt erfolgreich ein Element draußen habe und das Array somit eines kürzer ist (19 statt vorher 20), muss ich ja das 20. Element praktisch löschen bzw. freigeben.
Geht einfach
SetLength(Liste, 19);
oder muss da was anderes her?
Schattengeist - Sa 10.07.04 18:18
Was ist TDatenRec? Ein Objekt? dann etwas lustiger. Ein Record? Dann einfach die Liste kürzen.
iX0r - Sa 10.07.04 19:51
hier empfiehlt sich als datenstruktur natürlich eine verkette liste.
damit kannst du elemente sehr einfach entfernen, bedingung ist natürlich, daß du dich wein wenig mit pointern auskennst.
mfg
iX0r
Delete - Sa 10.07.04 21:11
Mit Hilfe der Suchfunktion und des eigenen gehirns gelöst. ^^
Tino - So 11.07.04 09:24
Poste doch mal deine Lösung... würde mich interessieren :-)
Delete - So 11.07.04 20:40
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TForm1.DeleteArrayIndex(var X: TListe; Index: Integer); var a:integer; begin if Index > High(X) then exit; if Index < Low(X) then exit; if Index = High(X) then begin SetLength(X, Length(X) - 1); Exit; end; for a:= index to length(X)-2 do X[a]:=X[a+1]; SetLength(X, Length(X) - 1); end;
...
DeleteArrayIndex(Liste, ListBox1.ItemIndex); |
So viel schonmal dazu.
Nun haben sich bei mir allerdings weitere Probleme ergeben. Ich möhte das dynamische Array mit Hilfe eines FileStreams in eine Datei bringen und zwar in folgender Struktur:
Passwort: String;
Length(Liste): Integer;
Und nun die Array-Elemente...
Bei Öffnen werden willkürlich irgendwelche Speicherbereiche ausgelesen wie zB. der Inhalt der Variable "FileName" oder auch Captions einiger Labels. Es folgen die Deklarationen des TDatenRec, des dyn. Array TListe und der Speicher bzw. Öffnen-Code:
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: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
| type TDatenRec = Record Titel, LoginName, Passwort, Information: String; end;
type Tliste = array of TDatenRec;
...
procedure TForm1.Speichern; var stream: TFileStream; FileName: string; Laenge:Integer; a:integer; begin FileName:=ExtractFilePath(Application.ExeName) + 'data.dat'; if not fileexists(FileName) then begin stream:= TFilestream.Create(Filename, fmcreate); stream.write(Passwort, SizeOf(Passwort)); a:=0; stream.write(a, SizeOf(integer)); stream.Free; end;
stream:= TFileStream.create(FileName, fmopenwrite); with stream do begin write(passwort, sizeof(passwort)); Seek(sizeOf(string), soFromBeginning); Laenge:=length(Liste); Write(Laenge, SizeOf(laenge)); for a:= 0 to length(Liste)-1 do write(Liste[a], SizeOf(TDatenRec)); Free; end; end;
procedure TForm1.FormCreate(Sender: TObject); var stream: TFileStream; FileName: string; Passwort: string; a:integer; begin Passwort:=''; FileName:=ExtractFilePath(Application.ExeName) + 'data.dat'; If not FileExists(FileNAme) then exit; stream:= TFileStream.create(FileName, fmopenread); with stream do begin Read(Passwort,SizeOf(String)); read(a, sizeOf(integer)); SetLength(Liste,a); for a:= 0 to length(liste)-1 do begin Read(Liste[a],SizeOf(TDatenRec)); ListBox1.Items.Add(Liste[a].Titel); end; end; stream.Free; end; |
Mache ich einen Denk- oder Unwissenheitsfehler?
Ich weiß unterdessen nicht einmal, ob das Problem beim Speichern oder Öffnen der Datei auftritt.
Würde mich über Hilfe sehr freuen!
Wenn jemand nen Screeni oder das Projekt bräuchte, bitte Bescheid sagen.
Anonymous - So 11.07.04 20:54
:? Vermutlich liegts an den Strings.
Versuch deine Strings mal so zu speichern:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var foo: integer; ... begin foo := length(str); stream.write(foo, 4); stream.write(@str[1]^, length(str)); end; |
Laden dann eben so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var foo: integer; ... begin stream.read(foo, 4); setlength(str, foo); stream.read(@str[1]^, length(str)); end; |
Delete - Mo 12.07.04 19:13
| obbschtkuche hat folgendes geschrieben: |
Delphi-Quelltext 1: 2: 3:
| stream.write(@str[1]^, length(str)); ... stream.read(@str[1]^, length(str)); | |
Also ich habe generell verstanden, wie Zeiger funktionieren. Nur ich verstehe die [1] in den beiden Zeilen nicht. Mit @ die Addresse von Str ermitteln und mit ^ den Speicherbereich auslesen. Aber warum die [1]?
Edit:
Hab eben den Code getestet. Funktioniert nicht so, wie du ihn geschrieben hast.
Aber so geht es:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| foo:=length(str); write(foo,4); write(str[1], length(str)); ... read(foo,4); setLength(str,foo); read(str[1], length(str)); |
Obwohl ich nach wie vor nicht verstehe, was die [1] zu bedeuten hat, funktioniert esnicht ohne sie.
maximus - Di 13.07.04 09:52
Hi, weil strings auch nur pointer sind und bei [1] fängt der eigentlich string an :wink:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 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!